PageSourceSearch

https://ahcon.dk/dist/magic.js?001

js ahcon.dk collected 2026-10-10 00:21:55 UTC 1,542,874 bytes, 38,173 lines download raw bytes

vendor: 4,295 bytes, lines 1-115
1/*
2 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
3 *
4 * Uses the built in easing capabilities added In jQuery 1.1
5 * to offer multiple easing options
6 *
7 * TERMS OF USE - jQuery Easing
8 * 
9 * Open source under the BSD License. 
10 * 
11 * Copyright В© 2008 George McGinley Smith
12 * All rights reserved.
13 * 
14 * Redistribution and use in source and binary forms, with or without modification, 
15 * are permitted provided that the following conditions are met:
16 * 
17 * Redistributions of source code must retain the above copyright notice, this list of 
18 * conditions and the following disclaimer.
19 * Redistributions in binary form must reproduce the above copyright notice, this list 
20 * of conditions and the following disclaimer in the documentation and/or other materials 
21 * provided with the distribution.
22 * 
23 * Neither the name of the author nor the names of contributors may be used to endorse 
24 * or promote products derived from this software without specific prior written permission.
25 * 
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
27 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
31 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
34 * OF THE POSSIBILITY OF SUCH DAMAGE. 
35 *
36*/
37
38// t: current time, b: begInnIng value, c: change In value, d: duration
39jQuery.easing['jswing'] = jQuery.easing['swing'];
40
41jQuery.extend( jQuery.easing,
42{
43	def: 'easeOutQuad',
44	swing: function (x, t, b, c, d) {
45		//alert(jQuery.easing.default);
46		return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
47	},
48	easeInQuad: function (x, t, b, c, d) {
49		return c*(t/=d)*t + b;
50	},
51	easeOutQuad: function (x, t, b, c, d) {
52		return -c *(t/=d)*(t-2) + b;
53	},
54	easeInOutQuad: function (x, t, b, c, d) {
55		if ((t/=d/2) < 1) return c/2*t*t + b;
56		return -c/2 * ((--t)*(t-2) - 1) + b;
57	},
58	easeInCubic: function (x, t, b, c, d) {
59		return c*(t/=d)*t*t + b;
60	},
61	easeOutCubic: function (x, t, b, c, d) {
62		return c*((t=t/d-1)*t*t + 1) + b;
63	},
64	easeInOutCubic: function (x, t, b, c, d) {
65		if ((t/=d/2) < 1) return c/2*t*t*t + b;
66		return c/2*((t-=2)*t*t + 2) + b;
67	},
68	easeInQuart: function (x, t, b, c, d) {
69		return c*(t/=d)*t*t*t + b;
70	},
71	easeOutQuart: function (x, t, b, c, d) {
72		return -c * ((t=t/d-1)*t*t*t - 1) + b;
73	},
74	easeInOutQuart: function (x, t, b, c, d) {
75		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
76		return -c/2 * ((t-=2)*t*t*t - 2) + b;
77	},
78	easeInQuint: function (x, t, b, c, d) {
79		return c*(t/=d)*t*t*t*t + b;
80	},
81	easeOutQuint: function (x, t, b, c, d) {
82		return c*((t=t/d-1)*t*t*t*t + 1) + b;
83	},
84	easeInOutQuint: function (x, t, b, c, d) {
85		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
86		return c/2*((t-=2)*t*t*t*t + 2) + b;
87	},
88	easeInSine: function (x, t, b, c, d) {
89		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
90	},
91	easeOutSine: function (x, t, b, c, d) {
92		return c * Math.sin(t/d * (Math.PI/2)) + b;
93	},
94	easeInOutSine: function (x, t, b, c, d) {
95		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
96	},
97	easeInExpo: function (x, t, b, c, d) {
98		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
99	},
100	easeOutExpo: function (x, t, b, c, d) {
101		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
102	},
103	easeInOutExpo: function (x, t, b, c, d) {
104		if (t==0) return b;
105		if (t==d) return b+c;
106		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
107		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
108	},
109	easeInCirc: function (x, t, b, c, d) {
110		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
111	},
112	easeOutCirc: function (x, t, b, c, d) {
113		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
114	},
115	easeInOutCirc: function (x, t, b, c, d) {
116		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
117		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
118	},
119	easeInElastic: function (x, t, b, c, d) {
120		var s=1.70158;var p=0;var a=c;
121		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
122		if (a < Math.abs(c)) { a=c; var s=p/4; }
123		else var s = p/(2*Math.PI) * Math.asin (c/a);
124		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
125	},
126	easeOutElastic: function (x, t, b, c, d) {
127		var s=1.70158;var p=0;var a=c;
128		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
129		if (a < Math.abs(c)) { a=c; var s=p/4; }
130		else var s = p/(2*Math.PI) * Math.asin (c/a);
131		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
132	},
133	easeInOutElastic: function (x, t, b, c, d) {
134		var s=1.70158;var p=0;var a=c;
135		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
136		if (a < Math.abs(c)) { a=c; var s=p/4; }
137		else var s = p/(2*Math.PI) * Math.asin (c/a);
138		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
139		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
140	},
141	easeInBack: function (x, t, b, c, d, s) {
142		if (s == undefined) s = 1.70158;
143		return c*(t/=d)*t*((s+1)*t - s) + b;
144	},
145	easeOutBack: function (x, t, b, c, d, s) {
146		if (s == undefined) s = 1.70158;
147		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
148	},
149	easeInOutBack: function (x, t, b, c, d, s) {
150		if (s == undefined) s = 1.70158; 
151		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
152		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
153	},
154	easeInBounce: function (x, t, b, c, d) {
155		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
156	},
157	easeOutBounce: function (x, t, b, c, d) {
158		if ((t/=d) < (1/2.75)) {
159			return c*(7.5625*t*t) + b;
160		} else if (t < (2/2.75)) {
161			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
162		} else if (t < (2.5/2.75)) {
163			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
164		} else {
165			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
166		}
167	},
168	easeInOutBounce: function (x, t, b, c, d) {
169		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
170		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
171	}
172});
173
174/*
175 *
176 * TERMS OF USE - EASING EQUATIONS
177 * 
178 * Open source under the BSD License. 
179 * 
180 * Copyright В© 2001 Robert Penner
181 * All rights reserved.
182 * 
183 * Redistribution and use in source and binary forms, with or without modification, 
184 * are permitted provided that the following conditions are met:
185 * 
186 * Redistributions of source code must retain the above copyright notice, this list of 
187 * conditions and the following disclaimer.
188 * Redistributions in binary form must reproduce the above copyright notice, this list 
189 * of conditions and the following disclaimer in the documentation and/or other materials 
190 * provided with the distribution.
191 * 
192 * Neither the name of the author nor the names of contributors may be used to endorse 
193 * or promote products derived from this software without specific prior written permission.
194 * 
195 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
196 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
197 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
198 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
199 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
200 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
201 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
202 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
203 * OF THE POSSIBILITY OF SUCH DAMAGE. 
204 *
205 */
206/*!
207 *
208 *  Copyright (c) David Bushell | http://dbushell.com/
209 *
210 */
211(function(window, document, undefined)
212{
213
214    // helper functions
215
216    var trim = function(str)
217    {
218        return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,'');
219    };
220
221    var hasClass = function(el, cn)
222    {
223        return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
224    };
225
226    var addClass = function(el, cn)
227    {
228        if (!hasClass(el, cn)) {
229            el.className = (el.className === '') ? cn : el.className + ' ' + cn;
230        }
231    };
232
233    var removeClass = function(el, cn)
234    {
235        el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
236    };
237
238    var hasParent = function(el, id)
239    {
240        if (el) {
241            do {
242                if (el.id === id) {
243                    return true;
244                }
245                if (el.nodeType === 9) {
246                    break;
247                }
248            }
249            while((el = el.parentNode));
250        }
251        return false;
252    };
253
254    // normalize vendor prefixes
255
256    var doc = document.documentElement;
257
258    var transform_prop = window.Modernizr.prefixed('transform'),
259        transition_prop = window.Modernizr.prefixed('transition'),
260        transition_end = (function() {
261            var props = {
262                'WebkitTransition' : 'webkitTransitionEnd',
263                'MozTransition'    : 'transitionend',
264                'OTransition'      : 'oTransitionEnd otransitionend',
265                'msTransition'     : 'MSTransitionEnd',
266                'transition'       : 'transitionend'
267            };
268            return props.hasOwnProperty(transition_prop) ? props[transition_prop] : false;
269        })();
270
271    window.App = (function()
272    {
273
274        var _init = false, app = { };
275
276        var inner = document.getElementById('inner-wrap'),
277
278            nav_open = false,
279
280            nav_class = 'js-nav';
281
282
283        app.init = function()
284        {
285            if (_init) {
286                return;
287            }
288            _init = true;
289
290            var closeNavEnd = function(e)
291            {
292                if (e && e.target === inner) {
293                    document.removeEventListener(transition_end, closeNavEnd, false);
294                }
295                nav_open = false;
296            };
297
298            app.closeNav =function()
299            {
300                if (nav_open) {
301                    // close navigation after transition or immediately
302                    var duration = (transition_end && transition_prop) ? parseFloat(window.getComputedStyle(inner, '')[transition_prop + 'Duration']) : 0;
303                    if (duration > 0) {
304                        document.addEventListener(transition_end, closeNavEnd, false);
305                    } else {
306                        closeNavEnd(null);
307                    }
308                }
309                removeClass(doc, nav_class);
310            };
311
312            app.openNav = function()
313            {
314                if (nav_open) {
315                    return;
316                }
317                addClass(doc, nav_class);
318                nav_open = true;
319            };
320
321            app.toggleNav = function(e)
322            {
323                if (nav_open && hasClass(doc, nav_class)) {
324                    app.closeNav();
325                } else {
326                    app.openNav();
327                }
328                if (e) {
329                    e.preventDefault();
330                }
331            };
332
333            // open nav with main "nav" button
334            document.getElementById('nav-open-btn').addEventListener('click', app.toggleNav, false);
335
336            // close nav with main "close" button
337            document.getElementById('nav-close-btn').addEventListener('click', app.toggleNav, false);
338
339            /* //we hide the document click, so we can use the dropdowns on the off-canvas menu
340            // close nav by touching the partial off-screen content
341            document.addEventListener('click', function(e)
342            {
343                if (nav_open && !hasParent(e.target, 'nav')) {
344                    e.preventDefault();
345                    app.closeNav();
346                }
347            },
348            true);
349            */
350
351            addClass(doc, 'js-ready');
352
353        };
354
355        return app;
356
357    })();
358
359    if (window.addEventListener) {
360        window.addEventListener('DOMContentLoaded', window.App.init, false);
361    }
362
363})(window, window.document);
364
365/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
366
367window.matchMedia || (window.matchMedia = function() {
368    "use strict";
369
370    // For browsers that support matchMedium api such as IE 9 and webkit
371    var styleMedia = (window.styleMedia || window.media);
372
373    // For those that don't support matchMedium
374    if (!styleMedia) {
375        var style       = document.createElement('style'),
376            script      = document.getElementsByTagName('script')[0],
377            info        = null;
378
379        style.type  = 'text/css';
380        style.id    = 'matchmediajs-test';
381
382        script.parentNode.insertBefore(style, script);
383
384        // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
385        info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;
386
387        styleMedia = {
388            matchMedium: function(media) {
389                var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }';
390
391                // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
392                if (style.styleSheet) {
393                    style.styleSheet.cssText = text;
394                } else {
395                    style.textContent = text;
396                }
397
398                // Test if media query is true or false
399                return info.width === '1px';
400            }
401        };
402    }
403
404    return function(media) {
405        return {
406            matches: styleMedia.matchMedium(media || 'all'),
407            media: media || 'all'
408        };
409    };
410}());
411
412/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */
413(function(){
414    // Bail out for browsers that have addListener support
415    if (window.matchMedia && window.matchMedia('all').addListener) {
416        return false;
417    }
418
419    var localMatchMedia = window.matchMedia,
420        hasMediaQueries = localMatchMedia('only all').matches,
421        isListening     = false,
422        timeoutID       = 0,    // setTimeout for debouncing 'handleChange'
423        queries         = [],   // Contains each 'mql' and associated 'listeners' if 'addListener' is used
424        handleChange    = function(evt) {
425            // Debounce
426            clearTimeout(timeoutID);
427
428            timeoutID = setTimeout(function() {
429                for (var i = 0, il = queries.length; i < il; i++) {
430                    var mql         = queries[i].mql,
431                        listeners   = queries[i].listeners || [],
432                        matches     = localMatchMedia(mql.media).matches;
433
434                    // Update mql.matches value and call listeners
435                    // Fire listeners only if transitioning to or from matched state
436                    if (matches !== mql.matches) {
437                        mql.matches = matches;
438
439                        for (var j = 0, jl = listeners.length; j < jl; j++) {
440                            listeners[j].call(window, mql);
441                        }
442                    }
443                }
444            }, 30);
445        };
446
447    window.matchMedia = function(media) {
448        var mql         = localMatchMedia(media),
449            listeners   = [],
450            index       = 0;
451
452        mql.addListener = function(listener) {
453            // Changes would not occur to css media type so return now (Affects IE <= 8)
454            if (!hasMediaQueries) {
455                return;
456            }
457
458            // Set up 'resize' listener for browsers that support CSS3 media queries (Not for IE <= 8)
459            // There should only ever be 1 resize listener running for performance
460            if (!isListening) {
461                isListening = true;
462                window.addEventListener('resize', handleChange, true);
463            }
464
465            // Push object only if it has not been pushed already
466            if (index === 0) {
467                index = queries.push({
468                    mql         : mql,
469                    listeners   : listeners
470                });
471            }
472
473            listeners.push(listener);
474        };
475
476        mql.removeListener = function(listener) {
477            for (var i = 0, il = listeners.length; i < il; i++){
478                if (listeners[i] === listener){
479                    listeners.splice(i, 1);
480                }
481            }
482        };
483
484        return mql;
485    };
486}());
487
488/*!
489 * enquire.js v2.1.2 - Awesome Media Queries in JavaScript
490 * Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/enquire.js
491 * License: MIT (http://www.opensource.org/licenses/mit-license.php)
492 */
493
494!function(a,b,c){var d=window.matchMedia;"undefined"!=typeof module&&module.exports?module.exports=c(d):"function"==typeof define&&define.amd?define(function(){return b[a]=c(d)}):b[a]=c(d)}("enquire",this,function(a){"use strict";function b(a,b){var c,d=0,e=a.length;for(d;e>d&&(c=b(a[d],d),c!==!1);d++);}function c(a){return"[object Array]"===Object.prototype.toString.apply(a)}function d(a){return"function"==typeof a}function e(a){this.options=a,!a.deferSetup&&this.setup()}function f(b,c){this.query=b,this.isUnconditional=c,this.handlers=[],this.mql=a(b);var d=this;this.listener=function(a){d.mql=a,d.assess()},this.mql.addListener(this.listener)}
494function g(){if(!a)throw new Error("matchMedia not present, legacy browsers require a polyfill");this.queries={},this.browserIsIncapable=!a("only all").matches}return e.prototype={setup:function(){this.options.setup&&this.options.setup(),this.initialised=!0},on:function(){!this.initialised&&this.setup(),this.options.match&&this.options.match()},off:function(){this.options.unmatch&&this.options.unmatch()},destroy:function(){this.options.destroy?this.options.destroy():this.off()},equals:function(a){return this.options===a||this.options.match===a}},f.prototype={addHandler:function(a){var b=new e(a);this.handlers.push(b),this.matches()&&b.on()},removeHandler:function(a){var c=this.handlers;b(c,function(b,d){return b.equals(a)?(b.destroy(),!c.splice(d,1)):void 0})},matches:function(){return this.mql.matches||this.isUnconditional},clear:function(){b(this.handlers,function(a){a.destroy()}),this.mql.removeListener(this.listener),this.handlers.length=0},assess:function(){var a=this.matches()?"on":"off";b(this.handlers,function(b){b[a]()})}},g.prototype={register:function(a,e,g){var h=this.queries,i=g&&this.browserIsIncapable;return h[a]||(h[a]=new f(a,i)),d(e)&&(e={match:e}),c(e)||(e=[e]),b(e,function(b){d(b)&&(b={match:b}),h[a].addHandler(b)}),this},unregister:function(a,b){var c=this.queries[a];return c&&(b?c.removeHandler(b):(c.clear(),delete this.queries[a])),this}},new g});
495/*!
496 * Bootstrap v3.3.2 (http://getbootstrap.com)
497 * Copyright 2011-2015 Twitter, Inc.
498 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
499 */
500if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.2",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.2",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&
vendor: 4,320 bytes, line 500
500c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.2",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({}
vendor: 4,713 bytes, line 500
500,f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.2",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.2",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".
500navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.divider):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="menu"]',g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="listbox"]',g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$backdrop=this.isShown=null,this.scrollbarWidth=0,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.2",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.options.backdrop&&d.adjustBackdrop(),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in").attr("aria-hidden",!1),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$element.find(".modal-dialog").one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('<div class="modal-backdrop '+e+'" />').prependTo(this.$element).on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.options.backdrop&&this.adjustBackdrop(),this.adjustDialog()},c.prototype.adjustBackdrop=function(){this.$backdrop.css("height",0).css("height",this.$element[0].scrollHeight)},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){this.bodyIsOverflowing=document.body.scrollHeight>document.documentElement.clientHeight,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right","")},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.3.2",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-m<p.top?"bottom":"right"==h&&k.right+l>p.width?"left":"left"==h&&k.left-l<p.left?"right":h,f.removeClass(n).addClass(h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=
vendor: 9,758 bytes, lines 500-501
500parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=this.tip(),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.2",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},c.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){var e=a.proxy(this.process,this);this.$body=a("body"),this.$scrollElement=a(a(c).is("body")?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",e),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.2",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b="offset",c=0;a.isWindow(this.$scrollElement[0])||(b="position",c=this.$scrollElement.scrollTop()),this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight();var d=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+c,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){d.offsets.push(this[0]),d.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.2",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()
501}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;
501e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.2",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a("body").height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
502(function ($) {
503  'use strict';
504
505  // Case insensitive search
506  $.expr[':'].icontains = function (obj, index, meta) {
507    return icontains($(obj).text(), meta[3]);
508  };
509
510  // Case and accent insensitive search
511  $.expr[':'].aicontains = function (obj, index, meta) {
512    return icontains($(obj).data('normalizedText') || $(obj).text(), meta[3]);
513  };
514
515  /**
516   * Actual implementation of the case insensitive search.
517   * @access private
518   * @param {String} haystack
519   * @param {String} needle
520   * @returns {boolean}
521   */
522  function icontains(haystack, needle) {
523    return haystack.toUpperCase().indexOf(needle.toUpperCase()) > -1;
524  }
525
526  /**
527   * Remove all diatrics from the given text.
528   * @access private
529   * @param {String} text
530   * @returns {String}
531   */
532  function normalizeToBase(text) {
533    var rExps = [
534      {re: /[\xC0-\xC6]/g, ch: "A"},
535      {re: /[\xE0-\xE6]/g, ch: "a"},
536      {re: /[\xC8-\xCB]/g, ch: "E"},
537      {re: /[\xE8-\xEB]/g, ch: "e"},
538      {re: /[\xCC-\xCF]/g, ch: "I"},
539      {re: /[\xEC-\xEF]/g, ch: "i"},
540      {re: /[\xD2-\xD6]/g, ch: "O"},
541      {re: /[\xF2-\xF6]/g, ch: "o"},
542      {re: /[\xD9-\xDC]/g, ch: "U"},
543      {re: /[\xF9-\xFC]/g, ch: "u"},
544      {re: /[\xC7-\xE7]/g, ch: "c"},
545      {re: /[\xD1]/g, ch: "N"},
546      {re: /[\xF1]/g, ch: "n"}
547    ];
548    $.each(rExps, function () {
549      text = text.replace(this.re, this.ch);
550    });
551    return text;
552  }
553
554
555  function htmlEscape(html) {
556    var escapeMap = {
557      '&': '&amp;',
558      '<': '&lt;',
559      '>': '&gt;',
560      '"': '&quot;',
561      "'": '&#x27;',
562      '`': '&#x60;'
563    };
564    var source = '(?:' + Object.keys(escapeMap).join('|') + ')',
565        testRegexp = new RegExp(source),
566        replaceRegexp = new RegExp(source, 'g'),
567        string = html == null ? '' : '' + html;
568    return testRegexp.test(string) ? string.replace(replaceRegexp, function (match) {
569      return escapeMap[match];
570    }) : string;
571  }
572
573  var Selectpicker = function (element, options, e) {
574    if (e) {
575      e.stopPropagation();
576      e.preventDefault();
577    }
578
579    this.$element = $(element);
580    this.$newElement = null;
581    this.$button = null;
582    this.$menu = null;
583    this.$lis = null;
584    this.options = options;
585
586    // If we have no title yet, try to pull it from the html title attribute (jQuery doesnt' pick it up as it's not a
587    // data-attribute)
588    if (this.options.title === null) {
589      this.options.title = this.$element.attr('title');
590    }
591
592    //Expose public methods
593    this.val = Selectpicker.prototype.val;
594    this.render = Selectpicker.prototype.render;
595    this.refresh = Selectpicker.prototype.refresh;
596    this.setStyle = Selectpicker.prototype.setStyle;
597    this.selectAll = Selectpicker.prototype.selectAll;
598    this.deselectAll = Selectpicker.prototype.deselectAll;
599    this.destroy = Selectpicker.prototype.remove;
600    this.remove = Selectpicker.prototype.remove;
601    this.show = Selectpicker.prototype.show;
602    this.hide = Selectpicker.prototype.hide;
603
604    this.init();
605  };
606
607  Selectpicker.VERSION = '1.6.3';
608
609  // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
610  Selectpicker.DEFAULTS = {
611    noneSelectedText: 'Nothing selected',
612    noneResultsText: 'No results match',
613    countSelectedText: function (numSelected, numTotal) {
614      return (numSelected == 1) ? "{0} item selected" : "{0} items selected";
615    },
616    maxOptionsText: function (numAll, numGroup) {
617      var arr = [];
618
619      arr[0] = (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)';
620      arr[1] = (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)';
621
622      return arr;
623    },
624    selectAllText: 'Select All',
625    deselectAllText: 'Deselect All',
626    multipleSeparator: ', ',
627    style: 'btn-default',
628    size: 'auto',
629    title: null,
630    selectedTextFormat: 'values',
631    width: false,
632    container: false,
633    hideDisabled: false,
634    showSubtext: false,
635    showIcon: true,
636    showContent: true,
637    dropupAuto: true,
638    header: false,
639    liveSearch: false,
640    actionsBox: false,
641    iconBase: 'glyphicon',
642    tickIcon: 'glyphicon-ok',
643    maxOptions: false,
644    mobile: false,
645    selectOnTab: false,
646    dropdownAlignRight: false,
647    searchAccentInsensitive: false
648  };
649
650  Selectpicker.prototype = {
651
652    constructor: Selectpicker,
653
654    init: function () {
655      var that = this,
656          id = this.$element.attr('id');
657
658      this.$element.hide();
659      this.multiple = this.$element.prop('multiple');
660      this.autofocus = this.$element.prop('autofocus');
661      this.$newElement = this.createView();
662      this.$element.after(this.$newElement);
663      this.$menu = this.$newElement.find('> .dropdown-menu');
664      this.$button = this.$newElement.find('> button');
665      this.$searchbox = this.$newElement.find('input');
666
667      if (this.options.dropdownAlignRight)
668        this.$menu.addClass('dropdown-menu-right');
669
670      if (typeof id !== 'undefined') {
671        this.$button.attr('data-id', id);
672        $('label[for="' + id + '"]').click(function (e) {
673          e.preventDefault();
674          that.$button.focus();
675        });
676      }
677
678      this.checkDisabled();
679      this.clickListener();
680      if (this.options.liveSearch) this.liveSearchListener();
681      this.render();
682      this.liHeight();
683      this.setStyle();
684      this.setWidth();
685      if (this.options.container) this.selectPosition();
686      this.$menu.data('this', this);
687      this.$newElement.data('this', this);
688      if (this.options.mobile) this.mobile();
689    },
690
691    createDropdown: function () {
692      // Options
693      // If we are multiple, then add the show-tick class by default
694      var multiple = this.multiple ? ' show-tick' : '',
695          inputGroup = this.$element.parent().hasClass('input-group') ? ' input-group-btn' : '',
696          autofocus = this.autofocus ? ' autofocus' : '',
697          btnSize = this.$element.parents().hasClass('form-group-lg') ? ' btn-lg' : (this.$element.parents().hasClass('form-group-sm') ? ' btn-sm' : '');
698      // Elements
699      var header = this.options.header ? '<div class="popover-title"><button type="button" class="close" aria-hidden="true">&times;</button>' + this.options.header + '</div>' : '';
700      var searchbox = this.options.liveSearch ? '<div class="bs-searchbox"><input type="text" class="input-block-level form-control" autocomplete="off" /></div>' : '';
701      var actionsbox = this.options.actionsBox ? '<div class="bs-actionsbox">' +
702      '<div class="btn-group btn-block">' +
703      '<button class="actions-btn bs-select-all btn btn-sm btn-default">' +
704      this.options.selectAllText +
705      '</button>' +
706      '<button class="actions-btn bs-deselect-all btn btn-sm btn-default">' +
707      this.options.deselectAllText +
708      '</button>' +
709      '</div>' +
710      '</div>' : '';
711      var drop =
712          '<div class="btn-group bootstrap-select' + multiple + inputGroup + '">' +
713          '<button type="button" class="btn dropdown-toggle selectpicker' + btnSize + '" data-toggle="dropdown"' + autofocus + '>' +
714          '<span class="filter-option pull-left"></span>&nbsp;' +
715          '<span class="caret"></span>' +
716          '</button>' +
717          '<div class="dropdown-menu open">' +
718          header +
719          searchbox +
720          actionsbox +
721          '<ul class="dropdown-menu inner selectpicker" role="menu">' +
722          '</ul>' +
723          '</div>' +
724          '</div>';
725
726      return $(drop);
727    },
728
729    createView: function () {
730      var $drop = this.createDropdown();
731      var $li = this.createLi();
732      $drop.find('ul').append($li);
733      return $drop;
734    },
735
736    reloadLi: function () {
737      //Remove all children.
738      this.destroyLi();
739      //Re build
740      var $li = this.createLi();
741      this.$menu.find('ul').append($li);
742    },
743
744    destroyLi: function () {
745      this.$menu.find('li').remove();
746    },
747
748    createLi: function () {
749      var that = this,
750          _li = [],
751          optID = 0;
752
753      // Helper functions
754      /**
755       * @param content
756       * @param [index]
757       * @param [classes]
758       * @returns {string}
759       */
760      var generateLI = function (content, index, classes) {
761        return '<li' +
762        (typeof classes !== 'undefined' ? ' class="' + classes + '"' : '') +
763        (typeof index !== 'undefined' | null === index ? ' data-original-index="' + index + '"' : '') +
764        '>' + content + '</li>';
765      };
766
767      /**
768       * @param text
769       * @param [classes]
770       * @param [inline]
771       * @param [optgroup]
772       * @returns {string}
773       */
774      var generateA = function (text, classes, inline, optgroup) {
775        var normText = normalizeToBase(htmlEscape(text));
776        return '<a tabindex="0"' +
777        (typeof classes !== 'undefined' ? ' class="' + classes + '"' : '') +
778        (typeof inline !== 'undefined' ? ' style="' + inline + '"' : '') +
779        (typeof optgroup !== 'undefined' ? 'data-optgroup="' + optgroup + '"' : '') +
780        ' data-normalized-text="' + normText + '"' +
781        '>
781' + text +
782        '<span class="' + that.options.iconBase + ' ' + that.options.tickIcon + ' check-mark"></span>' +
783        '</a>';
784      };
785
786      this.$element.find('option').each(function () {
787        var $this = $(this);
788
789        // Get the class and text for the option
790        var optionClass = $this.attr('class') || '',
791            inline = $this.attr('style'),
792            text = $this.data('content') ? $this.data('content') : $this.html(),
793            subtext = typeof $this.data('subtext') !== 'undefined' ? '<small class="muted text-muted">' + $this.data('subtext') + '</small>' : '',
794            icon = typeof $this.data('icon') !== 'undefined' ? '<span class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></span> ' : '',
795            isDisabled = $this.is(':disabled') || $this.parent().is(':disabled'),
796            index = $this[0].index;
797        if (icon !== '' && isDisabled) {
798          icon = '<span>' + icon + '</span>';
799        }
800
801        if (!$this.data('content')) {
802          // Prepend any icon and append any subtext to the main text.
803          text = icon + '<span class="text">' + text + subtext + '</span>';
804        }
805
806        if (that.options.hideDisabled && isDisabled) {
807          return;
808        }
809
810        if ($this.parent().is('optgroup') && $this.data('divider') !== true) {
811          if ($this.index() === 0) { // Is it the first option of the optgroup?
812            optID += 1;
813
814            // Get the opt group label
815            var label = $this.parent().attr('label');
816            var labelSubtext = typeof $this.parent().data('subtext') !== 'undefined' ? '<small class="muted text-muted">' + $this.parent().data('subtext') + '</small>' : '';
817            var labelIcon = $this.parent().data('icon') ? '<span class="' + that.options.iconBase + ' ' + $this.parent().data('icon') + '"></span> ' : '';
818            label = labelIcon + '<span class="text">' + label + labelSubtext + '</span>';
819
820            if (index !== 0 && _li.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown?
821              _li.push(generateLI('', null, 'divider'));
822            }
823
824            _li.push(generateLI(label, null, 'dropdown-header'));
825          }
826
827          _li.push(generateLI(generateA(text, 'opt ' + optionClass, inline, optID), index));
828        } else if ($this.data('divider') === true) {
829          _li.push(generateLI('', index, 'divider'));
830        } else if ($this.data('hidden') === true) {
831          _li.push(generateLI(generateA(text, optionClass, inline), index, 'hide is-hidden'));
832        } else {
833          _li.push(generateLI(generateA(text, optionClass, inline), index));
834        }
835      });
836
837      //If we are not multiple, we don't have a selected item, and we don't have a title, select the first element so something is set in the button
838      if (!this.multiple && this.$element.find('option:selected').length === 0 && !this.options.title) {
839        this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
840      }
841
842      return $(_li.join(''));
843    },
844
845    findLis: function () {
846      if (this.$lis == null) this.$lis = this.$menu.find('li');
847      return this.$lis;
848    },
849
850    /**
851     * @param [updateLi] defaults to true
852     */
853    render: function (updateLi) {
854      var that = this;
855
856      //Update the LI to match the SELECT
857      if (updateLi !== false) {
858        this.$element.find('option').each(function (index) {
859          that.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled'));
860          that.setSelected(index, $(this).is(':selected'));
861        });
862      }
863
864      this.tabIndex();
865      var notDisabled = this.options.hideDisabled ? ':not([disabled])' : '';
866      var selectedItems = this.$element.find('option:selected' + notDisabled).map(function () {
867        var $this = $(this);
868        var icon = $this.data('icon') && that.options.showIcon ? '<i class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></i> ' : '';
869        var subtext;
870        if (that.options.showSubtext && $this.attr('data-subtext') && !that.multiple) {
871          subtext = ' <small class="muted text-muted">' + $this.data('subtext') + '</small>';
872        } else {
873          subtext = '';
874        }
875        if ($this.data('content') && that.options.showContent) {
876          return $this.data('content');
877        } else if (typeof $this.attr('title') !== 'undefined') {
878          return $this.attr('title');
879        } else {
880          return icon + $this.html() + subtext;
881        }
882      }).toArray();
883
884      //Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled
885      //Convert all the values into a comma delimited string
886      var title = !this.multiple ? selectedItems[0] : selectedItems.join(this.options.multipleSeparator);
887
888      //If this is multi select, and the selectText type is count, the show 1 of 2 selected etc..
889      if (this.multiple && this.options.selectedTextFormat.indexOf('count') > -1) {
890        var max = this.options.selectedTextFormat.split('>');
891        if ((max.length > 1 && selectedItems.length > max[1]) || (max.length == 1 && selectedItems.length >= 2)) {
892          notDisabled = this.options.hideDisabled ? ', [disabled]' : '';
893          var totalCount = this.$element.find('option').not('[data-divider="true"], [data-hidden="true"]' + notDisabled).length,
894              tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedItems.length, totalCount) : this.options.countSelectedText;
895          title = tr8nText.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString());
896        }
897      }
898
899      this.options.title = this.$element.attr('title');
900
901      if (this.options.selectedTextFormat == 'static') {
902        title = this.options.title;
903      }
904
905      //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text
906      if (!title) {
907        title = typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText;
908      }
909
910      this.$button.attr('title', htmlEscape(title));
911      this.$newElement.find('.filter-option').html(title);
912    },
913
914    /**
915     * @param [style]
916     * @param [status]
917     */
918    setStyle: function (style, status) {
919      if (this.$element.attr('class')) {
920        this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|validate\[.*\]/gi, ''));
921      }
922
923      var buttonClass = style ? style : this.options.style;
924
925      if (status == 'add') {
926        this.$button.addClass(buttonClass);
927      } else if (status == 'remove') {
928        this.$button.removeClass(buttonClass);
929      } else {
930        this.$button.removeClass(this.options.style);
931        this.$button.addClass(buttonClass);
932      }
933    },
934
935    liHeight: function () {
936      if (this.options.size === false) return;
937
938      var $selectClone = this.$menu.parent().clone().find('> .dropdown-toggle').prop('autofocus', false).end().appendTo('body'),
939          $menuClone = $selectClone.addClass('open').find('> .dropdown-menu'),
940          liHeight = $menuClone.find('li').not('.divider').not('.dropdown-header').filter(':visible').children('a').outerHeight(),
941          headerHeight = this.options.header ? $menuClone.find('.popover-title').outerHeight() : 0,
942          searchHeight = this.options.liveSearch ? $menuClone.find('.bs-searchbox').outerHeight() : 0,
943          actionsHeight = this.options.actionsBox ? $menuClone.find('.bs-actionsbox').outerHeight() : 0;
944
945      $selectClone.remove();
946
947      this.$newElement
948          .data('liHeight', liHeight)
949          .data('headerHeight', headerHeight)
950          .data('searchHeight', searchHeight)
951          .data('actionsHeight', actionsHeight);
952    },
953
954    setSize: function () {
955      this.findLis();
956      var that = this,
957          menu = this.$menu,
958          menuInner = menu.find('.inner'),
959          selectHeight = this.$newElement.outerHeight(),
960          liHeight = this.$newElement.data('liHeight'),
961          headerHeight = this.$newElement.data('headerHeight'),
962          searchHeight = this.$newElement.data('searchHeight'),
963          actionsHeight = this.$newElement.data('actionsHeight'),
964          divHeight = this.$lis.filter('.divider').outerHeight(true),
965          menuPadding = parseInt(menu.css('padding-top')) +
966              parseInt(menu.css('padding-bottom')) +
967              parseInt(menu.css('border-top-width')) +
968              parseInt(menu.css('border-bottom-width')),
969          notDisabled = this.options.hideDisabled ? ', .disabled' : '',
970          $window = $(window),
971          menuExtras = menuPadding + parseInt(menu.css('margin-top')) + parseInt(menu.css('margin-bottom')) + 2,
972          menuHeight,
973          selectOffsetTop,
974          selectOffsetBot,
975          posVert = function () {
976            // JQuery defines a scrollTop function, but in pure JS it's a property
977            //noinspection JSValidateTypes
978            selectOffsetTop = that.$newElement.offset().top - $window.scrollTop();
979            selectOffsetBot = $window.height() - selectOffsetTop - selectHeight;
980          };
981      posVert();
982      if (this.options.header) menu.css('padding-top', 0);
983
984      if (this.options.size == 'auto') {
985        var getSize = function () {
986          var minHeight,
987              lisVis = that.$lis.not('.hide');
988
989          posVert();
990          menuHeight = selectOffsetBot - menuExtras;
991
992          if (that.options.dropupAuto) {
993            that.$newElement.toggleClass('dropup', (selectOffsetTop > selectOffsetBot) && ((menuHeight - menuExtras) < menu.height()));
994          }
995          if (that.$newElement.hasClass('dropup')) {
996            menuHeight = selectOffsetTop - menuExtras;
997          }
998
999          if ((lisVis.length + lisVis.filter('.dropdown-header').length) > 3) {
1000            minHeight = liHeight * 3 + menuExtras - 2;
1001          } else {
1002            minHeight = 0;
1003          }
1004
1005          menu.css({
1006            'max-height': menuHeight + 'px',
1007            'overflow': 'hidden',
1008            'min-height': minHeight + headerHeight + searchHeight + actionsHeight + 'px'
1009          });
1010          menuInner.css({
1011            'max-height': menuHeight - headerHeight - searchHeight - actionsHeight - menuPadding + 'px',
1012            'overflow-y': 'auto',
1013            'min-height': Math.max(minHeight - menuPadding, 0) + 'px'
1014          });
1015        };
1016        getSize();
1017        this.$searchbox.off('input.getSize propertychange.getSize').on('input.getSize propertychange.getSize', getSize);
1018        $(window).off('resize.getSize').on('resize.getSize', getSize);
1019        $(window).off('scroll.getSize').on('scroll.getSize', getSize);
1020      } else if (this.options.size && this.options.size != 'auto' && menu.find('li' + notDisabled).length > this.options.size) {
1021        var optIndex = this.$lis.not('.divider' + notDisabled).find(' > *').slice(0, this.options.size).last().parent().index();
1022        var divLength = this.$lis.slice(0, optIndex + 1).filter('.divider').length;
1023        menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding;
1024        if (that.options.dropupAuto) {
1025          //noinspection JSUnusedAssignment
1026          this.$newElement.toggleClass('dropup', (selectOffsetTop > selectOffsetBot) && (menuHeight < menu.height()));
1027        }
1028        menu.css({'max-height': menuHeight + headerHeight + searchHeight + actionsHeight + 'px', 'overflow': 'hidden'});
1029        menuInner.css({'max-height': menuHeight - menuPadding + 'px', 'overflow-y': 'auto'});
1030      }
1031    },
1032
1033    setWidth: function () {
1034      if (this.options.width == 'auto') {
1035        this.$menu.css('min-width', '0');
1036
1037        // Get correct width if element hidden
1038        var selectClone = this.$newElement.clone().appendTo('body');
1039        var ulWidth = selectClone.find('> .dropdown-menu').css('width');
1040        var btnWidth = selectClone.css('width', 'auto').find('> button').css('width');
1041        selectClone.remove();
1042
1043        // Set width to whatever's larger, button title or longest option
1044        this.$newElement.css('width', Math.max(parseInt(ulWidth), parseInt(btnWidth)) + 'px');
1045      } else if (this.options.width == 'fit') {
1046        // Remove inline min-width so width can be changed from 'auto'
1047        this.$menu.css('min-width', '');
1048        this.$newElement.css('width', '').addClass('fit-width');
1049      } else if (this.options.width) {
1050        // Remove inline min-width so width can be changed from 'auto'
1051        this.$menu.css('min-width', '');
1052        this.$newElement.css('width', this.options.width);
1053      } else {
1054        // Remove inline min-width/width so width can be changed
1055        this.$menu.css('min-width', '');
1056        this.$newElement.css('width', '');
1057      }
1058      // Remove fit-width class if width is changed programmatically
1059      if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
1060        this.$newElement.removeClass('fit-width');
1061      }
1062    },
1063
1064    selectPosition: function () {
1065      var that = this,
1066          drop = '<div />',
1067          $drop = $(drop),
1068          pos,
1069          actualHeight,
1070          getPlacement = function ($element) {
1071            $drop.addClass($element.attr('class').replace(/form-control/gi, '')).toggleClass('dropup', $element.hasClass('dropup'));
1072            pos = $element.offset();
1073            actualHeight = $element.hasClass('dropup') ? 0 : $element[0].offsetHeight;
1074            $drop.css({
1075              'top': pos.top + actualHeight,
1076              'left': pos.left,
1077              'width': $element[0].offsetWidth,
1078              'position': 'absolute'
1079            });
1080          };
1081      this.$newElement.on('click', function () {
1082        if (that.isDisabled()) {
1083          return;
1084        }
1085        getPlacement($(this));
1086        $drop.appendTo(that.options.container);
1087        $drop.toggleClass('open', !$(this).hasClass('open'));
1088        $drop.append(that.$menu);
1089      });
1090      $(window).resize(function () {
1091        getPlacement(that.$newElement);
1092      });
1093      $(window).on('scroll', function () {
1094        getPlacement(that.$newElement);
1095      });
1096      $('html').on('click', function (e) {
1097        if ($(e.target).closest(that.$newElement).length < 1) {
1098          $drop.removeClass('open');
1099        }
1100      });
1101    },
1102
1103    setSelected: function (index, selected) {
1104      this.findLis();
1105      this.$lis.filter('[data-original-index="' + index + '"]').toggleClass('selected', selected);
1106    },
1107
1108    setDisabled: function (index, disabled) {
1109      this.findLis();
1110      if (disabled) {
1111        this.$lis.filter('[data-original-index="' + index + '"]').addClass('disabled').find('a').attr('href', '#').attr('tabindex', -1);
1112      } else {
1113        this.$lis.filter('[data-original-index="' + index + '"]').removeClass('disabled').find('a').removeAttr('href').attr('tabindex', 0);
1114      }
1115    },
1116
1117    isDisabled: function () {
1118      return this.$element.is(':disabled');
1119    },
1120
1121    checkDisabled: function () {
1122      var that = this;
1123
1124      if (this.isDisabled()) {
1125        this.$button.addClass('disabled').attr('tabindex', -1);
1126      } else {
1127        if (this.$button.hasClass('disabled')) {
1128          this.$button.removeClass('disabled');
1129        }
1130
1131        if (this.$button.attr('tabindex') == -1) {
1132          if (!this.$element.data('tabindex')) this.$button.removeAttr('tabindex');
1133        }
1134      }
1135
1136      this.$button.click(function () {
1137        return !that.isDisabled();
1138      });
1139    },
1140
1141    tabIndex: function () {
1142      if (this.$element.is('[tabindex]')) {
1143        this.$element.data('tabindex', this.$element.attr('tabindex'));
1144        this.$button.attr('tabindex', this.$element.data('tabindex'));
1145      }
1146    },
1147
1148    clickListener: function () {
1149      var that = this;
1150
1151      this.$newElement.on('touchstart.dropdown', '.dropdown-menu', function (e) {
1152        e.stopPropagation();
1153      });
1154
1155      this.$newElement.on('click', function () {
1156      
1156  that.setSize();
1157        if (!that.options.liveSearch && !that.multiple) {
1158          setTimeout(function () {
1159            that.$menu.find('.selected a').focus();
1160          }, 10);
1161        }
1162      });
1163
1164      this.$menu.on('click', 'li a', function (e) {
1165        var $this = $(this),
1166            clickedIndex = $this.parent().data('originalIndex'),
1167            prevValue = that.$element.val(),
1168            prevIndex = that.$element.prop('selectedIndex');
1169
1170        // Don't close on multi choice menu
1171        if (that.multiple) {
1172          e.stopPropagation();
1173        }
1174
1175        e.preventDefault();
1176
1177        //Don't run if we have been disabled
1178        if (!that.isDisabled() && !$this.parent().hasClass('disabled')) {
1179          var $options = that.$element.find('option'),
1180              $option = $options.eq(clickedIndex),
1181              state = $option.prop('selected'),
1182              $optgroup = $option.parent('optgroup'),
1183              maxOptions = that.options.maxOptions,
1184              maxOptionsGrp = $optgroup.data('maxOptions') || false;
1185
1186          if (!that.multiple) { // Deselect all others if not multi select box
1187            $options.prop('selected', false);
1188            $option.prop('selected', true);
1189            that.$menu.find('.selected').removeClass('selected');
1190            that.setSelected(clickedIndex, true);
1191          } else { // Toggle the one we have chosen if we are multi select.
1192            $option.prop('selected', !state);
1193            that.setSelected(clickedIndex, !state);
1194            $this.blur();
1195
1196            if ((maxOptions !== false) || (maxOptionsGrp !== false)) {
1197              var maxReached = maxOptions < $options.filter(':selected').length,
1198                  maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;
1199
1200              if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
1201                if (maxOptions && maxOptions == 1) {
1202                  $options.prop('selected', false);
1203                  $option.prop('selected', true);
1204                  that.$menu.find('.selected').removeClass('selected');
1205                  that.setSelected(clickedIndex, true);
1206                } else if (maxOptionsGrp && maxOptionsGrp == 1) {
1207                  $optgroup.find('option:selected').prop('selected', false);
1208                  $option.prop('selected', true);
1209                  var optgroupID = $this.data('optgroup');
1210
1211                  that.$menu.find('.selected').has('a[data-optgroup="' + optgroupID + '"]').removeClass('selected');
1212
1213                  that.setSelected(clickedIndex, true);
1214                } else {
1215                  var maxOptionsArr = (typeof that.options.maxOptionsText === 'function') ?
1216                          that.options.maxOptionsText(maxOptions, maxOptionsGrp) : that.options.maxOptionsText,
1217                      maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
1218                      maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
1219                      $notify = $('<div class="notify"></div>');
1220                  // If {var} is set in array, replace it
1221                  /** @deprecated */
1222                  if (maxOptionsArr[2]) {
1223                    maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
1224                    maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
1225                  }
1226
1227                  $option.prop('selected', false);
1228
1229                  that.$menu.append($notify);
1230
1231                  if (maxOptions && maxReached) {
1232                    $notify.append($('<div>' + maxTxt + '</div>'));
1233                    that.$element.trigger('maxReached.bs.select');
1234                  }
1235
1236                  if (maxOptionsGrp && maxReachedGrp) {
1237                    $notify.append($('<div>' + maxTxtGrp + '</div>'));
1238                    that.$element.trigger('maxReachedGrp.bs.select');
1239                  }
1240
1241                  setTimeout(function () {
1242                    that.setSelected(clickedIndex, false);
1243                  }, 10);
1244
1245                  $notify.delay(750).fadeOut(300, function () {
1246                    $(this).remove();
1247                  });
1248                }
1249              }
1250            }
1251          }
1252
1253          if (!that.multiple) {
1254            that.$button.focus();
1255          } else if (that.options.liveSearch) {
1256            that.$searchbox.focus();
1257          }
1258
1259          // Trigger select 'change'
1260          if ((prevValue != that.$element.val() && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) {
1261            that.$element.change();
1262          }
1263        }
1264      });
1265
1266      this.$menu.on('click', 'li.disabled a, .popover-title, .popover-title :not(.close)', function (e) {
1267        if (e.target == this) {
1268          e.preventDefault();
1269          e.stopPropagation();
1270          if (!that.options.liveSearch) {
1271            that.$button.focus();
1272          } else {
1273            that.$searchbox.focus();
1274          }
1275        }
1276      });
1277
1278      this.$menu.on('click', 'li.divider, li.dropdown-header', function (e) {
1279        e.preventDefault();
1280        e.stopPropagation();
1281        if (!that.options.liveSearch) {
1282          that.$button.focus();
1283        } else {
1284          that.$searchbox.focus();
1285        }
1286      });
1287
1288      this.$menu.on('click', '.popover-title .close', function () {
1289        that.$button.focus();
1290      });
1291
1292      this.$searchbox.on('click', function (e) {
1293        e.stopPropagation();
1294      });
1295
1296
1297      this.$menu.on('click', '.actions-btn', function (e) {
1298        if (that.options.liveSearch) {
1299          that.$searchbox.focus();
1300        } else {
1301          that.$button.focus();
1302        }
1303
1304        e.preventDefault();
1305        e.stopPropagation();
1306
1307        if ($(this).is('.bs-select-all')) {
1308          that.selectAll();
1309        } else {
1310          that.deselectAll();
1311        }
1312        that.$element.change();
1313      });
1314
1315      this.$element.change(function () {
1316        that.render(false);
1317      });
1318    },
1319
1320    liveSearchListener: function () {
1321      var that = this,
1322          no_results = $('<li class="no-results"></li>');
1323
1324      this.$newElement.on('click.dropdown.data-api touchstart.dropdown.data-api', function () {
1325        that.$menu.find('.active').removeClass('active');
1326        if (!!that.$searchbox.val()) {
1327          that.$searchbox.val('');
1328          that.$lis.not('.is-hidden').removeClass('hide');
1329          if (!!no_results.parent().length) no_results.remove();
1330        }
1331        if (!that.multiple) that.$menu.find('.selected').addClass('active');
1332        setTimeout(function () {
1333          that.$searchbox.focus();
1334        }, 10);
1335      });
1336
1337      this.$searchbox.on('click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api', function (e) {
1338        e.stopPropagation();
1339      });
1340
1341      this.$searchbox.on('input propertychange', function () {
1342        if (that.$searchbox.val()) {
1343
1344          if (that.options.searchAccentInsensitive) {
1345            that.$lis.not('.is-hidden').removeClass('hide').find('a').not(':aicontains(' + normalizeToBase(that.$searchbox.val()) + ')').parent().addClass('hide');
1346          } else {
1347            that.$lis.not('.is-hidden').removeClass('hide').find('a').not(':icontains(' + that.$searchbox.val() + ')').parent().addClass('hide');
1348          }
1349
1350          if (!that.$menu.find('li').filter(':visible:not(.no-results)').length) {
1351            if (!!no_results.parent().length) no_results.remove();
1352            no_results.html(that.options.noneResultsText + ' "' + htmlEscape(that.$searchbox.val()) + '"').show();
1353            that.$menu.find('li').last().after(no_results);
1354          } else if (!!no_results.parent().length) {
1355            no_results.remove();
1356          }
1357
1358        } else {
1359          that.$lis.not('.is-hidden').removeClass('hide');
1360          if (!!no_results.parent().length) no_results.remove();
1361        }
1362
1363        that.$menu.find('li.active').removeClass('active');
1364        that.$menu.find('li').filter(':visible:not(.divider)').eq(0).addClass('active').find('a').focus();
1365        $(this).focus();
1366      });
1367    },
1368
1369    val: function (value) {
1370      if (typeof value !== 'undefined') {
1371        this.$element.val(value);
1372        this.render();
1373
1374        return this.$element;
1375      } else {
1376        return this.$element.val();
1377      }
1378    },
1379
1380    selectAll: function () {
1381      this.findLis();
1382      this.$lis.not('.divider').not('.disabled').not('.selected').filter(':visible').find('a').click();
1383    },
1384
1385    deselectAll: function () {
1386      this.findLis();
1387      this.$lis.not('.divider').not('.disabled').filter('.selected').filter(':visible').find('a').click();
1388    },
1389
1390    keydown: function (e) {
1391      var $this = $(this),
1392          $parent = ($this.is('input')) ? $this.parent().parent() : $this.parent(),
1393          $items,
1394          that = $parent.data('this'),
1395          index,
1396          next,
1397          first,
1398          last,
1399          prev,
1400          nextPrev,
1401          prevIndex,
1402          isActive,
1403          keyCodeMap = {
1404            32: ' ',
1405            48: '0',
1406            49: '1',
1407            50: '2',
1408            51: '3',
1409            52: '4',
1410            53: '5',
1411            54: '6',
1412            55: '7',
1413            56: '8',
1414            57: '9',
1415            59: ';',
1416            65: 'a',
1417            66: 'b',
1418            67: 'c',
1419            68: 'd',
1420            69: 'e',
1421            70: 'f',
1422            71: 'g',
1423            72: 'h',
1424            73: 'i',
1425            74: 'j',
1426            75: 'k',
1427            76: 'l',
1428            77: 'm',
1429            78: 'n',
1430            79: 'o',
1431            80: 'p',
1432            81: 'q',
1433            82: 'r',
1434            83: 's',
1435            84: 't',
1436            85: 'u',
1437            86: 'v',
1438            87: 'w',
1439            88: 'x',
1440            89: 'y',
1441            90: 'z',
1442            96: '0',
1443            97: '1',
1444            98: '2',
1445            99: '3',
1446            100: '4',
1447            101: '5',
1448            102: '6',
1449            103: '7',
1450            104: '8',
1451            105: '9'
1452          };
1453
1454      if (that.options.liveSearch) $parent = $this.parent().parent();
1455
1456      if (that.options.container) $parent = that.$menu;
1457
1458      $items = $('[role=menu] li a', $parent);
1459
1460      isActive = that.$menu.parent().hasClass('open');
1461
1462      if (!isActive && /([0-9]|[A-z])/.test(String.fromCharCode(e.keyCode))) {
1463        if (!that.options.container) {
1464          that.setSize();
1465          that.$menu.parent().addClass('open');
1466          isActive = true;
1467        } else {
1468          that.$newElement.trigger('click');
1469        }
1470        that.$searchbox.focus();
1471      }
1472
1473      if (that.options.liveSearch) {
1474        if (/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && that.$menu.find('.active').length === 0) {
1475          e.preventDefault();
1476          that.$menu.parent().removeClass('open');
1477          that.$button.focus();
1478        }
1479        $items = $('[role=menu] li:not(.divider):not(.dropdown-header):visible', $parent);
1480        if (!$this.val() && !/(38|40)/.test(e.keyCode.toString(10))) {
1481          if ($items.filter('.active').length === 0) {
1482            if (that.options.searchAccentInsensitive) {
1483              $items = that.$newElement.find('li').filter(':aicontains(' + normalizeToBase(keyCodeMap[e.keyCode]) + ')');
1484            } else {
1485              $items = that.$newElement.find('li').filter(':icontains(' + keyCodeMap[e.keyCode] + ')');
1486            }
1487          }
1488        }
1489      }
1490
1491      if (!$items.length) return;
1492
1493      if (/(38|40)/.test(e.keyCode.toString(10))) {
1494        index = $items.index($items.filter(':focus'));
1495        first = $items.parent(':not(.disabled):visible').first().index();
1496        last = $items.parent(':not(.disabled):visible').last().index();
1497        next = $items.eq(index).parent().nextAll(':not(.disabled):visible').eq(0).index();
1498        prev = $items.eq(index).parent().prevAll(':not(.disabled):visible').eq(0).index();
1499        nextPrev = $items.eq(next).parent().prevAll(':not(.disabled):visible').eq(0).index();
1500
1501        if (that.options.liveSearch) {
1502          $items.each(function (i) {
1503            if ($(this).is(':not(.disabled)')) {
1504              $(this).data('index', i);
1505            }
1506          });
1507          index = $items.index($items.filter('.active'));
1508          first = $items.filter(':not(.disabled):visible').first().data('index');
1509          last = $items.filter(':not(.disabled):visible').last().data('index');
1510          next = $items.eq(index).nextAll(':not(.disabled):visible').eq(0).data('index');
1511          prev = $items.eq(index).prevAll(':not(.disabled):visible').eq(0).data('index');
1512          nextPrev = $items.eq(next).prevAll(':not(.disabled):visible').eq(0).data('index');
1513        }
1514
1515        prevIndex = $this.data('prevIndex');
1516
1517        if (e.keyCode == 38) {
1518          if (that.options.liveSearch) index -= 1;
1519          if (index != nextPrev && index > prev) index = prev;
1520          if (index < first) index = first;
1521          if (index == prevIndex) index = last;
1522        }
1523
1524        if (e.keyCode == 40) {
1525          if (that.options.liveSearch) index += 1;
1526          if (index == -1) index = 0;
1527          if (index != nextPrev && index < next) index = next;
1528          if (index > last) index = last;
1529          if (index == prevIndex) index = first;
1530        }
1531
1532        $this.data('prevIndex', index);
1533
1534        if (!that.options.liveSearch) {
1535          $items.eq(index).focus();
1536        } else {
1537          e.preventDefault();
1538          if (!$this.is('.dropdown-toggle')) {
1539            $items.removeClass('active');
1540            $items.eq(index).addClass('active').find('a').focus();
1541            $this.focus();
1542          }
1543        }
1544
1545      } else if (!$this.is('input')) {
1546        var keyIndex = [],
1547            count,
1548            prevKey;
1549
1550        $items.each(function () {
1551          if ($(this).parent().is(':not(.disabled)')) {
1552            if ($.trim($(this).text().toLowerCase()).substring(0, 1) == keyCodeMap[e.keyCode]) {
1553              keyIndex.push($(this).parent().index());
1554            }
1555          }
1556        });
1557
1558        count = $(document).data('keycount');
1559        count++;
1560        $(document).data('keycount', count);
1561
1562        prevKey = $.trim($(':focus').text().toLowerCase()).substring(0, 1);
1563
1564        if (prevKey != keyCodeMap[e.keyCode]) {
1565          count = 1;
1566          $(document).data('keycount', count);
1567        } else if (count >= keyIndex.length) {
1568          $(document).data('keycount', 0);
1569          if (count > keyIndex.length) count = 1;
1570        }
1571
1572        $items.eq(keyIndex[count - 1]).focus();
1573      }
1574
1575      // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu.
1576      if ((/(13|32)/.test(e.keyCode.toString(10)) || (/(^9$)/.test(e.keyCode.toString(10)) && that.options.selectOnTab)) && isActive) {
1577        if (!/(32)/.test(e.keyCode.toString(10))) e.preventDefault();
1578        if (!that.options.liveSearch) {
1579          $(':focus').click();
1580        } else if (!/(32)/.test(e.keyCode.toString(10))) {
1581          that.$menu.find('.active a').click();
1582          $this.focus();
1583        }
1584        $(document).data('keycount', 0);
1585      }
1586
1587      if ((/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && (that.multiple || that.options.liveSearch)) || (/(27)/.test(e.keyCode.toString(10)) && !isActive)) {
1588        that.$menu.parent().removeClass('open');
1589        that.$button.focus();
1590      }
1591    },
1592
1593    mobile: function () {
1594      this.$element.addClass('mobile-device').appendTo(this.$newElement);
1595      if (this.options.container) this.$menu.hide();
1596    },
1597
1598    refresh: function () {
1599      this.$lis = null;
1600      this.reloadLi();
1601      this.render();
1602      this.setWidth();
1603      this.setStyle();
1604      this.checkDisabled();
1605      this.liHeight();
1606    },
1607
1608    update: function () {
1609      this.reloadLi();
1610      this.setWidth();
1611      this.setStyle();
1612      this.checkDisabled();
1613      this.liHeight();
1614    },
1615
1616    hide: function () {
1617      this.$newElement.hide();
1618    },
1619
1620    show: function () {
1621      this.$newElement.show();
1622    },
1623
1624    remove: function () {
1625      this.$newElement.remove();
1626      this.$element.remove();
1627    }
1628  };
1629
1630  // SELECTPICKER PLUGIN DEFINITION
1631  // ==============================
1632  function Plugin(option, event) {
1633    // get the args of the outer function..
1634    var args = arguments;
1635    // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
1636    // to get lost
1637    //noinspection JSDuplicatedDeclaration
1638    var _option = option,
1639        option = args[0],
1640        event = args[1];
1641    [].shift.apply(args);
1642
1643    // This fixes a bug in the js implementation on android 2.3 #715
1644    if (typeof option == 'undefined') {
1645      option = _option;
1646    }
1647
1648    var value;
1649    var chain = this.each(function () {
1650      var $this = $(this);
1651      if ($this.is('select')) {
1652        var data = $this.data('selectpicker'),
1653            options = typeof option == 'object' && option;
1654
1655        if (!data) {
1656          var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, $this.data(), options);
1657          $this.data('selectpicker', (data = new Selectpicker(this, config, event)));
1658        } else if (options) {
1659          for (var i in options) {
1660            if (options.hasOwnProperty(i)) {
1661              data.options[i] = options[i];
1662            }
1663          }
1664        }
1665
1666        if (typeof option == 'string') {
1667          if (data[option] instanceof Function) {
1668            value = data[option].apply(data, args);
1669          } else {
1670            value = data.options[option];
1671          }
1672        }
1673      }
1674    });
1675
1676    if (typeof value !== 'undefined') {
1677      //noinspection JSUnusedAssignment
1678      return value;
1679    } else {
1680      return chain;
1681    }
1682  }
1683
1684  var old = $.fn.selectpicker;
1685  $.fn.selectpicker = Plugin;
1686  $.fn.selectpicker.Constructor = Selectpicker;
1687
1688  // SELECTPICKER NO CONFLICT
1689  // ========================
1690  $.fn.selectpicker.noConflict = function () {
1691    $.fn.selectpicker = old;
1692    return this;
1693  };
1694
1695  $(document)
1696      .data('keycount', 0)
1697      .on('keydown', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bs-searchbox input', Selectpicker.prototype.keydown)
1698      .on('focusin.modal', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bs-searchbox input', function (e) {
1699        e.stopPropagation();
1700      });
1701
1702  // SELECTPICKER DATA-API
1703  // =====================
1704  $(window).on('load.bs.select.data-api', function () {
1705    $('.selectpicker').each(function () {
1706      var $selectpicker = $(this);
1707      Plugin.call($selectpicker, $selectpicker.data());
1708    })
1709  });
1710})(jQuery);
1711
1712/*!
1713 * VERSION: 1.16.0
1714 * DATE: 2015-03-01
1715 * UPDATES AND DOCS AT: http://greensock.com
1716 * 
1717 * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
1718 *
1719 * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
1720 * This work is subject to the terms at http://greensock.com/standard-license or for
1721 * Club GreenSock members, the software agreement that was issued with your membership.
1722 * 
1723 * @author: Jack Doyle, [email protected]
1724 **/
1725var _gsScope="undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window;(_gsScope._gsQueue||(_gsScope._gsQueue=[])).push(function(){"use strict";_gsScope._gsDefine("TweenMax",["core.Animation","core.SimpleTimeline","TweenLite"],function(t,e,i){var s=function(t){var e,i=[],s=t.length;for(e=0;e!==s;i.push(t[e++]));return i},r=function(t,e,s){i.call(this,t,e,s),this._cycle=0,this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._dirty=!0,this.render=r.prototype.render},n=1e-10,a=i._internals,o=a.isSelector,h=a.isArray,l=r.prototype=i.to({},.1,{}),_=[];r.version="1.16.0",l.constructor=r,l.kill()._gc=!1,r.killTweensOf=r.killDelayedCallsTo=i.killTweensOf,r.getTweensOf=i.getTweensOf,r.lagSmoothing=i.lagSmoothing,r.ticker=i.ticker,r.render=i.render,l.invalidate=function(){return this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._uncache(!0),i.prototype.invalidate.call(this)},l.updateTo=function(t,e){var s,r=this.ratio,n=this.vars.immediateRender||t.immediateRender;e&&this._startTime<this._timeline._time&&(this._startTime=this._timeline._time,this._uncache(!1),this._gc?this._enabled(!0,!1):this._timeline.insert(this,this._startTime-this._delay));for(s in t)this.vars[s]=t[s];if(this._initted||n)if(e)this._initted=!1,n&&this.render(0,!0,!0);else if(this._gc&&this._enabled(!0,!1),this._notifyPluginsOfEnabled&&this._firstPT&&i._onPluginEvent("_onDisable",this),this._time/this._duration>.998){var a=this._time;this.render(0,!0,!1),this._initted=!1,this.render(a,!0,!1)}else if(this._time>0||n){this._initted=!1,this._init();for(var o,h=1/(1-r),l=this._firstPT;l;)o=l.s+l.c,l.c*=h,l.s=o-l.c,l=l._next}return this},l.render=function(t,e,i){this._initted||0===this._duration&&this.vars.repeat&&this.invalidate();var s,r,o,h,l,u,p,f,c=this._dirty?this.totalDuration():this._totalDuration,m=this._time,d=this._totalTime,g=this._cycle,v=this._duration,y=this._rawPrevTime;if(t>=c?(this._totalTime=c,this._cycle=this._repeat,this._yoyo&&0!==(1&this._cycle)?(this._time=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0):(this._time=v,this.ratio=this._ease._calcEnd?this._ease.getRatio(1):1),this._reversed||(s=!0,r="onComplete"),0===v&&(this._initted||!this.vars.lazy||i)&&(this._startTime===this._timeline._duration&&(t=0),(0===t||0>y||y===n)&&y!==t&&(i=!0,y>n&&(r="onReverseComplete")),this._rawPrevTime=f=!e||t||y===t?t:n)):1e-7>t?(this._totalTime=this._time=this._cycle=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0,(0!==d||0===v&&y>0)&&(r="onReverseComplete",s=this._reversed),0>t&&(this._active=!1,0===v&&(this._initted||!this.vars.lazy||i)&&(y>=0&&(i=!0),this._rawPrevTime=f=!e||t||y===t?t:n)),this._initted||(i=!0)):(this._totalTime=this._time=t,0!==this._repeat&&(h=v+this._repeatDelay,this._cycle=this._totalTime/h>>0,0!==this._cycle&&this._cycle===this._totalTime/h&&this._cycle--,this._time=this._totalTime-this._cycle*h,this._yoyo&&0!==(1&this._cycle)&&(this._time=v-this._time),this._time>v?this._time=v:0>this._time&&(this._time=0)),this._easeType?(l=this._time/v,u=this._easeType,p=this._easePower,(1===u||3===u&&l>=.5)&&(l=1-l),3===u&&(l*=2),1===p?l*=l:2===p?l*=l*l:3===p?l*=l*l*l:4===p&&(l*=l*l*l*l),this.ratio=1===u?1-l:2===u?l:.5>this._time/v?l/2:1-l/2):this.ratio=this._ease.getRatio(this._time/v)),m===this._time&&!i&&g===this._cycle)return d!==this._totalTime&&this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUp
vendor: 9,856 bytes, line 1725
1725dateScope||this,this.vars.onUpdateParams||_)),void 0;if(!this._initted){if(this._init(),!this._initted||this._gc)return;if(!i&&this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration))return this._time=m,this._totalTime=d,this._rawPrevTime=y,this._cycle=g,a.lazyTweens.push(this),this._lazy=[t,e],void 0;this._time&&!s?this.ratio=this._ease.getRatio(this._time/v):s&&this._ease._calcEnd&&(this.ratio=this._ease.getRatio(0===this._time?0:1))}for(this._lazy!==!1&&(this._lazy=!1),this._active||!this._paused&&this._time!==m&&t>=0&&(this._active=!0),0===d&&(2===this._initted&&t>0&&this._init(),this._startAt&&(t>=0?this._startAt.render(t,e,i):r||(r="_dummyGS")),this.vars.onStart&&(0!==this._totalTime||0===v)&&(e||this.vars.onStart.apply(this.vars.onStartScope||this,this.vars.onStartParams||_))),o=this._firstPT;o;)o.f?o.t[o.p](o.c*this.ratio+o.s):o.t[o.p]=o.c*this.ratio+o.s,o=o._next;this._onUpdate&&(0>t&&this._startAt&&this._startTime&&this._startAt.render(t,e,i),e||(this._totalTime!==d||s)&&this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||_)),this._cycle!==g&&(e||this._gc||this.vars.onRepeat&&this.vars.onRepeat.apply(this.vars.onRepeatScope||this,this.vars.onRepeatParams||_)),r&&(!this._gc||i)&&(0>t&&this._startAt&&!this._onUpdate&&this._startTime&&this._startAt.render(t,e,i),s&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[r]&&this.vars[r].apply(this.vars[r+"Scope"]||this,this.vars[r+"Params"]||_),0===v&&this._rawPrevTime===n&&f!==n&&(this._rawPrevTime=0))},r.to=function(t,e,i){return new r(t,e,i)},r.from=function(t,e,i){return i.runBackwards=!0,i.immediateRender=0!=i.immediateRender,new r(t,e,i)},r.fromTo=function(t,e,i,s){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,new r(t,e,s)},r.staggerTo=r.allTo=function(t,e,n,a,l,u,p){a=a||0;var f,c,m,d,g=n.delay||0,v=[],y=function(){n.onComplete&&n.onComplete.apply(n.onCompleteScope||this,arguments),l.apply(p||this,u||_)};for(h(t)||("string"==typeof t&&(t=i.selector(t)||t),o(t)&&(t=s(t))),t=t||[],0>a&&(t=s(t),t.reverse(),a*=-1),f=t.length-1,m=0;f>=m;m++){c={};for(d in n)c[d]=n[d];c.delay=g,m===f&&l&&(c.onComplete=y),v[m]=new r(t[m],e,c),g+=a}return v},r.staggerFrom=r.allFrom=function(t,e,i,s,n,a,o){return i.runBackwards=!0,i.immediateRender=0!=i.immediateRender,r.staggerTo(t,e,i,s,n,a,o)},r.staggerFromTo=r.allFromTo=function(t,e,i,s,n,a,o,h){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,r.staggerTo(t,e,s,n,a,o,h)},r.delayedCall=function(t,e,i,s,n){return new r(e,0,{delay:t,onComplete:e,onCompleteParams:i,onCompleteScope:s,onReverseComplete:e,onReverseCompleteParams:i,onReverseCompleteScope:s,immediateRender:!1,useFrames:n,overwrite:0})},r.set=function(t,e){return new r(t,0,e)},r.isTweening=function(t){return i.getTweensOf(t,!0).length>0};var u=function(t,e){for(var s=[],r=0,n=t._first;n;)n instanceof i?s[r++]=n:(e&&(s[r++]=n),s=s.concat(u(n,e)),r=s.length),n=n._next;return s},p=r.getAllTweens=function(e){return u(t._rootTimeline,e).concat(u(t._rootFramesTimeline,e))};r.killAll=function(t,i,s,r){null==i&&(i=!0),null==s&&(s=!0);var n,a,o,h=p(0!=r),l=h.length,_=i&&s&&r;for(o=0;l>o;o++)a=h[o],(_||a instanceof e||(n=a.target===a.vars.onComplete)&&s||i&&!n)&&(t?a.totalTime(a._reversed?0:a.totalDuration()):a._enabled(!1,!1))},r.killChildTweensOf=function(t,e){if(null!=t){var n,l,_,u,p,f=a.tweenLookup;if("string"==typeof t&&(t=i.selector(t)||t),o(t)&&(t=s(t)),h(t))for(u=t.length;--u>-1;)r.killChildTweensOf(t[u],e);else{n=[];for(_ in f)for(l=f[_].target.parentNode;l;)l===t&&(n=n.concat(f[_].tweens)),l=l.parentNode;for(p=n.length,u=0;p>u;u++)e&&n[u].totalTime(n[u].totalDuration()),n[u]._enabled(!1,!1)}}};var f=function(t,i,s,r){i=i!==!1,s=s!==!1,r=r!==!1;for(var n,a,o=p(r),h=i&&s&&r,l=o.length;--l>-1;)a=o[l],(h||a instanceof e||(n=a.target===a.vars.onComplete)&&s||i&&!n)&&a.paused(t)};return r.pauseAll=function(t,e,i){f(!0,t,e,i)},r.resumeAll=function(t,e,i){f(!1,t,e,i)},r.globalTimeScale=function(e){var s=t._rootTimeline,r=i.ticker.time;return arguments.length?(e=e||n,s._startTime=r-(r-s._startTime)*s._timeScale/e,s=t._rootFramesTimeline,r=i.ticker.frame,s._startTime=r-(r-s._startTime)*s._timeScale/e,s._timeScale=t._rootTimeline._timeScale=e,e):s._timeScale},l.progress=function(t){return arguments.length?this.totalTime(this.duration()*(this._yoyo&&0!==(1&this._cycle)?1-t:t)+this._cycle*(this._duration+this._repeatDelay),!1):this._time/this.duration()},l.totalProgress=function(t){return arguments.length?this.totalTime(this.totalDuration()*t,!1):this._totalTime/this.totalDuration()},l.time=function(t,e){return arguments.length?(this._dirty&&this.totalDuration(),t>this._duration&&(t=this._duration),this._yoyo&&0!==(1&this._cycle)?t=this._duration-t+this._cycle*(this._duration+this._repeatDelay):0!==this._repeat&&(t+=this._cycle*(this._duration+this._repeatDelay)),this.totalTime(t,e)):this._time},l.duration=function(e){return arguments.length?t.prototype.duration.call(this,e):this._duration},l.totalDuration=function(t){return arguments.length?-1===this._repeat?this:this.duration((t-this._repeat*this._repeatDelay)/(this._repeat+1)):(this._dirty&&(this._totalDuration=-1===this._repeat?999999999999:this._duration*(this._repeat+1)+this._repeatDelay*this._repeat,this._dirty=!1),this._totalDuration)},l.repeat=function(t){return arguments.length?(this._repeat=t,this._uncache(!0)):this._repeat},l.repeatDelay=function(t){return arguments.length?(this._repeatDelay=t,this._uncache(!0)):this._repeatDelay},l.yoyo=function(t){return arguments.length?(this._yoyo=t,this):this._yoyo},r},!0),_gsScope._gsDefine("TimelineLite",["core.Animation","core.SimpleTimeline","TweenLite"],function(t,e,i){var s=function(t){e.call(this,t),this._labels={},this.autoRemoveChildren=this.vars.autoRemoveChildren===!0,this.smoothChildTiming=this.vars.smoothChildTiming===!0,this._sortChildren=!0,this._onUpdate=this.vars.onUpdate;var i,s,r=this.vars;for(s in r)i=r[s],h(i)&&-1!==i.join("").indexOf("{self}")&&(r[s]=this._swapSelfInParams(i));h(r.tweens)&&this.add(r.tweens,0,r.align,r.stagger)},r=1e-10,n=i._internals,a=s._internals={},o=n.isSelector,h=n.isArray,l=n.lazyTweens,_=n.lazyRender,u=[],p=_gsScope._gsDefine.globals,f=function(t){var e,i={};for(e in t)i[e]=t[e];return i},c=a.pauseCallback=function(t,e,i,s){var n,a=t._timeline,o=a._totalTime,h=t._startTime,l=t.ratio?r:0,_=t.ratio?0:r;if(e||!this._forcingPlayhead){for(a.pause(h),n=t._prev;n&&n._startTime===h;)n._rawPrevTime=_,n=n._prev;for(n=t._next;n&&n._startTime===h;)n._rawPrevTime=l,n=n._next;e&&e.apply(s||a,i||u),this._forcingPlayhead&&a.seek(o)}},m=function(t){var e,i=[],s=t.length;for(e=0;e!==s;i.push(t[e++]));return i},d=s.prototype=new e;return s.version="1.16.0",d.constructor=s,d.kill()._gc=d._forcingPlayhead=!1,d.to=function(t,e,s,r){var n=s.repeat&&p.TweenMax||i;return e?this.add(new n(t,e,s),r):this.set(t,s,r)},d.from=function(t,e,s,r){return this.add((s.repeat&&p.TweenMax||i).from(t,e,s),r)},d.fromTo=function(t,e,s,r,n){var a=r.repeat&&p.TweenMax||i;return e?this.add(a.fromTo(t,e,s,r),n):this.set(t,r,n)},d.staggerTo=function(t,e,r,n,a,h,l,_){var u,p=new s({onComplete:h,onCompleteParams:l,onCompleteScope:_,smoothChildTiming:this.smoothChildTiming});for("string"==typeof t&&(t=i.selector(t)||t),t=t||[],o(t)&&(t=m(t)),n=n||0,0>n&&(t=m(t),t.reverse(),n*=-1),u=0;t.length>u;u++)r.startAt&&(r.startAt=f(r.startAt)),p.to(t[u],e,f(r),u*n);return this.add(p,a)},d.staggerFrom=function(t,e,i,s,r,n,a,o){return i.immediateRender=0!=i.immediateRender,i.runBackwards=!0,this.staggerTo(t,e,i,s,r,n,a,o)},d.staggerFromTo=function(t,e,i,s,r,n,a,o,h){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,this.staggerTo(t,e,s,r,n,a,o,h)},d.call=function(t,e,s,r){return this.add(i.delayedCall(0,t,e,s),r)},d.set=function(t,e,s){return s=this._parseTimeOrLabel(s,0,!0),null==e.immediateRender&&(e.immediateRender=s===this._time&&!this._paused),this.add(new i(t,0,e),s)},s.exportRoot=function(t,e){t=t||{},null==t.smoothChildTiming&&(t.smoothChildTiming=!0);var r,n,a=new s(t),o=a._timeline;for(null==e&&(e=!0),o._remove(a,!0),a._startTime=0,a._rawPrevTime=a._time=a._totalTime=o._time,r=o._first;r;)n=r._next,e&&r instanceof i&&r.target===r.vars.onComplete||a.add(r,r._startTime-r._delay),r=n;return o.add(a,0),a},d.add=function(r,n,a,o){var l,_,u,p,f,c;if("number"!=typeof n&&(n=this._parseTimeOrLabel(n,0,!0,r)),!(r instanceof t)){if(r instanceof Array||r&&r.push&&h(r)){for(a=a||"normal",o=o||0,l=n,_=r.length,u=0;_>u;u++)h(p=r[u])&&(p=new s({tweens:p})),this.add(p,l),"string"!=typeof p&&"function"!=typeof p&&("sequence"===a?l=p._startTime+p.totalDuration()/p._timeScale:"start"===a&&(p._startTime-=p.delay())),l+=o;return this._uncache(!0)}if("string"==typeof r)return this.addLabel(r,n);if("function"!=typeof r)throw"Cannot add "+r+" into the timeline; it is not a tween, timeline, function, or string.";r=i.delayedCall(0,r)}if(e.prototype.add.call(this,r,n),(this._gc||this._time===this._duration)&&!this._paused&&this._duration<this.duration())for(f=this,c=f.rawTime()>r._startTime;f._timeline;)c&&f._timeline.smoothChildTiming?f.totalTime(f._totalTime,!0):f._gc&&f._enabled(!0,!1),f=f._timeline;return this},d.remove=function(e){if(e instanceof t)return this._remove(e,!1);if(e instanceof Array||e&&e.push&&h(e)){for(var i=e.length;--i>-1;)this.remove(e[i]);return this}return"string"==typeof e?this.removeLabel(e):this.kill(null,e)},d._remove=function(t,i){e.prototype._remove.call(this,t,i);var s=this._last;return s?this._time>s._startTime+s._totalDuration/s._timeScale&&(this._time=this.duration(),this._totalTime=this._totalDuration):this._time=this._totalTime=this._duration=this._totalDuration=0,this},d.append=function(t,e){return this.add(t,this._parseTimeOrLabel(null,e,!0,t))}
1725,d.insert=d.insertMultiple=function(t,e,i,s){return this.add(t,e||0,i,s)},d.appendMultiple=function(t,e,i,s){return this.add(t,this._parseTimeOrLabel(null,e,!0,t),i,s)},d.addLabel=function(t,e){return this._labels[t]=this._parseTimeOrLabel(e),this},d.addPause=function(t,e,s,r){var n=i.delayedCall(0,c,["{self}",e,s,r],this);return n.data="isPause",this.add(n,t)},d.removeLabel=function(t){return delete this._labels[t],this},d.getLabelTime=function(t){return null!=this._labels[t]?this._labels[t]:-1},d._parseTimeOrLabel=function(e,i,s,r){var n;if(r instanceof t&&r.timeline===this)this.remove(r);else if(r&&(r instanceof Array||r.push&&h(r)))for(n=r.length;--n>-1;)r[n]instanceof t&&r[n].timeline===this&&this.remove(r[n]);if("string"==typeof i)return this._parseTimeOrLabel(i,s&&"number"==typeof e&&null==this._labels[i]?e-this.duration():0,s);if(i=i||0,"string"!=typeof e||!isNaN(e)&&null==this._labels[e])null==e&&(e=this.duration());else{if(n=e.indexOf("="),-1===n)return null==this._labels[e]?s?this._labels[e]=this.duration()+i:i:this._labels[e]+i;i=parseInt(e.charAt(n-1)+"1",10)*Number(e.substr(n+1)),e=n>1?this._parseTimeOrLabel(e.substr(0,n-1),0,s):this.duration()}return Number(e)+i},d.seek=function(t,e){return this.totalTime("number"==typeof t?t:this._parseTimeOrLabel(t),e!==!1)},d.stop=function(){return this.paused(!0)},d.gotoAndPlay=function(t,e){return this.play(t,e)},d.gotoAndStop=function(t,e){return this.pause(t,e)},d.render=function(t,e,i){this._gc&&this._enabled(!0,!1);var s,n,a,o,h,p=this._dirty?this.totalDuration():this._totalDuration,f=this._time,c=this._startTime,m=this._timeScale,d=this._paused;if(t>=p)this._totalTime=this._time=p,this._reversed||this._hasPausedChild()||(n=!0,o="onComplete",0===this._duration&&(0===t||0>this._rawPrevTime||this._rawPrevTime===r)&&this._rawPrevTime!==t&&this._first&&(h=!0,this._rawPrevTime>r&&(o="onReverseComplete"))),this._rawPrevTime=this._duration||!e||t||this._rawPrevTime===t?t:r,t=p+1e-4;else if(1e-7>t)if(this._totalTime=this._time=0,(0!==f||0===this._duration&&this._rawPrevTime!==r&&(this._rawPrevTime>0||0>t&&this._rawPrevTime>=0))&&(o="onReverseComplete",n=this._reversed),0>t)this._active=!1,this._timeline.autoRemoveChildren&&this._reversed?(h=n=!0,o="onReverseComplete"):this._rawPrevTime>=0&&this._first&&(h=!0),this._rawPrevTime=t;else{if(this._rawPrevTime=this._duration||!e||t||this._rawPrevTime===t?t:r,0===t&&n)for(s=this._first;s&&0===s._startTime;)s._duration||(n=!1),s=s._next;t=0,this._initted||(h=!0)}else this._totalTime=this._time=this._rawPrevTime=t;if(this._time!==f&&this._first||i||h){if(this._initted||(this._initted=!0),this._active||!this._paused&&this._time!==f&&t>0&&(this._active=!0),0===f&&this.vars.onStart&&0!==this._time&&(e||this.vars.onStart.apply(this.vars.onStartScope||this,this.vars.onStartParams||u)),this._time>=f)for(s=this._first;s&&(a=s._next,!this._paused||d);)(s._active||s._startTime<=this._time&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=a;else for(s=this._last;s&&(a=s._prev,!this._paused||d);)(s._active||f>=s._startTime&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=a;this._onUpdate&&(e||(l.length&&_(),this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||u))),o&&(this._gc||(c===this._startTime||m!==this._timeScale)&&(0===this._time||p>=this.totalDuration())&&(n&&(l.length&&_(),this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[o]&&this.vars[o].apply(this.vars[o+"Scope"]||this,this.vars[o+"Params"]||u)))}},d._hasPausedChild=function(){for(var t=this._first;t;){if(t._paused||t instanceof s&&t._hasPausedChild())return!0;t=t._next}return!1},d.getChildren=function(t,e,s,r){r=r||-9999999999;for(var n=[],a=this._first,o=0;a;)r>a._startTime||(a instanceof i?e!==!1&&(n[o++]=a):(s!==!1&&(n[o++]=a),t!==!1&&(n=n.concat(a.getChildren(!0,e,s)),o=n.length))),a=a._next;return n},d.getTweensOf=function(t,e){var s,r,n=this._gc,a=[],o=0;for(n&&this._enabled(!0,!0),s=i.getTweensOf(t),r=s.length;--r>-1;)(s[r].timeline===this||e&&this._contains(s[r]))&&(a[o++]=s[r]);return n&&this._enabled(!1,!0),a},d.recent=function(){return this._recent},d._contains=function(t){for(var e=t.timeline;e;){if(e===this)return!0;e=e.timeline}return!1}
vendor: 21,482 bytes, lines 1725-1726
1725,d.shiftChildren=function(t,e,i){i=i||0;for(var s,r=this._first,n=this._labels;r;)r._startTime>=i&&(r._startTime+=t),r=r._next;if(e)for(s in n)n[s]>=i&&(n[s]+=t);return this._uncache(!0)},d._kill=function(t,e){if(!t&&!e)return this._enabled(!1,!1);for(var i=e?this.getTweensOf(e):this.getChildren(!0,!0,!1),s=i.length,r=!1;--s>-1;)i[s]._kill(t,e)&&(r=!0);return r},d.clear=function(t){var e=this.getChildren(!1,!0,!0),i=e.length;for(this._time=this._totalTime=0;--i>-1;)e[i]._enabled(!1,!1);return t!==!1&&(this._labels={}),this._uncache(!0)},d.invalidate=function(){for(var e=this._first;e;)e.invalidate(),e=e._next;return t.prototype.invalidate.call(this)},d._enabled=function(t,i){if(t===this._gc)for(var s=this._first;s;)s._enabled(t,!0),s=s._next;return e.prototype._enabled.call(this,t,i)},d.totalTime=function(){this._forcingPlayhead=!0;var e=t.prototype.totalTime.apply(this,arguments);return this._forcingPlayhead=!1,e},d.duration=function(t){return arguments.length?(0!==this.duration()&&0!==t&&this.timeScale(this._duration/t),this):(this._dirty&&this.totalDuration(),this._duration)},d.totalDuration=function(t){if(!arguments.length){if(this._dirty){for(var e,i,s=0,r=this._last,n=999999999999;r;)e=r._prev,r._dirty&&r.totalDuration(),r._startTime>n&&this._sortChildren&&!r._paused?this.add(r,r._startTime-r._delay):n=r._startTime,0>r._startTime&&!r._paused&&(s-=r._startTime,this._timeline.smoothChildTiming&&(this._startTime+=r._startTime/this._timeScale),this.shiftChildren(-r._startTime,!1,-9999999999),n=0),i=r._startTime+r._totalDuration/r._timeScale,i>s&&(s=i),r=e;this._duration=this._totalDuration=s,this._dirty=!1}return this._totalDuration}return 0!==this.totalDuration()&&0!==t&&this.timeScale(this._totalDuration/t),this},d.paused=function(e){if(!e)for(var i=this._first,s=this._time;i;)i._startTime===s&&"isPause"===i.data&&(i._rawPrevTime=s),i=i._next;return t.prototype.paused.apply(this,arguments)},d.usesFrames=function(){for(var e=this._timeline;e._timeline;)e=e._timeline;return e===t._rootFramesTimeline},d.rawTime=function(){return this._paused?this._totalTime:(this._timeline.rawTime()-this._startTime)*this._timeScale},s},!0),_gsScope._gsDefine("TimelineMax",["TimelineLite","TweenLite","easing.Ease"],function(t,e,i){var s=function(e){t.call(this,e),this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._cycle=0,this._yoyo=this.vars.yoyo===!0,this._dirty=!0},r=1e-10,n=[],a=e._internals,o=a.lazyTweens,h=a.lazyRender,l=new i(null,null,1,0),_=s.prototype=new t;return _.constructor=s,_.kill()._gc=!1,s.version="1.16.0",_.invalidate=function(){return this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._uncache(!0),t.prototype.invalidate.call(this)},_.addCallback=function(t,i,s,r){return this.add(e.delayedCall(0,t,s,r),i)},_.removeCallback=function(t,e){if(t)if(null==e)this._kill(null,t);else for(var i=this.getTweensOf(t,!1),s=i.length,r=this._parseTimeOrLabel(e);--s>-1;)i[s]._startTime===r&&i[s]._enabled(!1,!1);return this},_.removePause=function(e){return this.removeCallback(t._internals.pauseCallback,e)},_.tweenTo=function(t,i){i=i||{};var s,r,a,o={ease:l,useFrames:this.usesFrames(),immediateRender:!1};for(r in i)o[r]=i[r];return o.time=this._parseTimeOrLabel(t),s=Math.abs(Number(o.time)-this._time)/this._timeScale||.001,a=new e(this,s,o),o.onStart=function(){a.target.paused(!0),a.vars.time!==a.target.time()&&s===a.duration()&&a.duration(Math.abs(a.vars.time-a.target.time())/a.target._timeScale),i.onStart&&i.onStart.apply(i.onStartScope||a,i.onStartParams||n)},a},_.tweenFromTo=function(t,e,i){i=i||{},t=this._parseTimeOrLabel(t),i.startAt={onComplete:this.seek,onCompleteParams:[t],onCompleteScope:this},i.immediateRender=i.immediateRender!==!1;var s=this.tweenTo(e,i);return s.duration(Math.abs(s.vars.time-t)/this._timeScale||.001)},_.render=function(t,e,i){this._gc&&this._enabled(!0,!1);var s,a,l,_,u,p,f=this._dirty?this.totalDuration():this._totalDuration,c=this._duration,m=this._time,d=this._totalTime,g=this._startTime,v=this._timeScale,y=this._rawPrevTime,T=this._paused,w=this._cycle;if(t>=f)this._locked||(this._totalTime=f,this._cycle=this._repeat),this._reversed||this._hasPausedChild()||(a=!0,_="onComplete",0===this._duration&&(0===t||0>y||y===r)&&y!==t&&this._first&&(u=!0,y>r&&(_="onReverseComplete"))),this._rawPrevTime=this._duration||!e||t||this._rawPrevTime===t?t:r,this._yoyo&&0!==(1&this._cycle)?this._time=t=0:(this._time=c,t=c+1e-4);else if(1e-7>t)if(this._locked||(this._totalTime=this._cycle=0),this._time=0,(0!==m||0===c&&y!==r&&(y>0||0>t&&y>=0)&&!this._locked)&&(_="onReverseComplete",a=this._reversed),0>t)this._active=!1,this._timeline.autoRemoveChildren&&this._reversed?(u=a=!0,_="onReverseComplete"):y>=0&&this._first&&(u=!0),this._rawPrevTime=t;else{if(this._rawPrevTime=c||!e||t||this._rawPrevTime===t?t:r,0===t&&a)for(s=this._first;s&&0===s._startTime;)s._duration||(a=!1),s=s._next;t=0,this._initted||(u=!0)}else 0===c&&0>y&&(u=!0),this._time=this._rawPrevTime=t,this._locked||(this._totalTime=t,0!==this._repeat&&(p=c+this._repeatDelay,this._cycle=this._totalTime/p>>0,0!==this._cycle&&this._cycle===this._totalTime/p&&this._cycle--,this._time=this._totalTime-this._cycle*p,this._yoyo&&0!==(1&this._cycle)&&(this._time=c-this._time),this._time>c?(this._time=c,t=c+1e-4):0>this._time?this._time=t=0:t=this._time));if(this._cycle!==w&&!this._locked){var x=this._yoyo&&0!==(1&w),b=x===(this._yoyo&&0!==(1&this._cycle)),P=this._totalTime,S=this._cycle,k=this._rawPrevTime,R=this._time;if(this._totalTime=w*c,w>this._cycle?x=!x:this._totalTime+=c,this._time=m,this._rawPrevTime=0===c?y-1e-4:y,this._cycle=w,this._locked=!0,m=x?0:c,this.render(m,e,0===c),e||this._gc||this.vars.onRepeat&&this.vars.onRepeat.apply(this.vars.onRepeatScope||this,this.vars.onRepeatParams||n),b&&(m=x?c+1e-4:-1e-4,this.render(m,!0,!1)),this._locked=!1,this._paused&&!T)return;this._time=R,this._totalTime=P,this._cycle=S,this._rawPrevTime=k}if(!(this._time!==m&&this._first||i||u))return d!==this._totalTime&&this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||n)),void 0;if(this._initted||(this._initted=!0),this._active||!this._paused&&this._totalTime!==d&&t>0&&(this._active=!0),0===d&&this.vars.onStart&&0!==this._totalTime&&(e||this.vars.onStart.apply(this.vars.onStartScope||this,this.vars.onStartParams||n)),this._time>=m)for(s=this._first;s&&(l=s._next,!this._paused||T);)(s._active||s._startTime<=this._time&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=l;else for(s=this._last;s&&(l=s._prev,!this._paused||T);)(s._active||m>=s._startTime&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=l;this._onUpdate&&(e||(o.length&&h(),this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||n))),_&&(this._locked||this._gc||(g===this._startTime||v!==this._timeScale)&&(0===this._time||f>=this.totalDuration())&&(a&&(o.length&&h(),this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[_]&&this.vars[_].apply(this.vars[_+"Scope"]||this,this.vars[_+"Params"]||n)))},_.getActive=function(t,e,i){null==t&&(t=!0),null==e&&(e=!0),null==i&&(i=!1);var s,r,n=[],a=this.getChildren(t,e,i),o=0,h=a.length;for(s=0;h>s;s++)r=a[s],r.isActive()&&(n[o++]=r);return n},_.getLabelAfter=function(t){t||0!==t&&(t=this._time);var e,i=this.getLabelsArray(),s=i.length;for(e=0;s>e;e++)if(i[e].time>t)return i[e].name;return null},_.getLabelBefore=function(t){null==t&&(t=this._time);for(var e=this.getLabelsArray(),i=e.length;--i>-1;)if(t>e[i].time)return e[i].name;return null},_.getLabelsArray=function(){var t,e=[],i=0;for(t in this._labels)e[i++]={time:this._labels[t],name:t};return e.sort(function(t,e){return t.time-e.time}),e},_.progress=function(t,e){return arguments.length?this.totalTime(this.duration()*(this._yoyo&&0!==(1&this._cycle)?1-t:t)+this._cycle*(this._duration+this._repeatDelay),e):this._time/this.duration()},_.totalProgress=function(t,e){return arguments.length?this.totalTime(this.totalDuration()*t,e):this._totalTime/this.totalDuration()},_.totalDuration=function(e){return arguments.length?-1===this._repeat?this:this.duration((e-this._repeat*this._repeatDelay)/(this._repeat+1)):(this._dirty&&(t.prototype.totalDuration.call(this),this._totalDuration=-1===this._repeat?999999999999:this._duration*(this._repeat+1)+this._repeatDelay*this._repeat),this._totalDuration)},_.time=function(t,e){return arguments.length?(this._dirty&&this.totalDuration(),t>this._duration&&(t=this._duration),this._yoyo&&0!==(1&this._cycle)?t=this._duration-t+this._cycle*(this._duration+this._repeatDelay):0!==this._repeat&&(t+=this._cycle*(this._duration+this._repeatDelay)),this.totalTime(t,e)):this._time},_.repeat=function(t){return arguments.length?(this._repeat=t,this._uncache(!0)):this._repeat},_.repeatDelay=function(t){return arguments.length?(this._repeatDelay=t,this._uncache(!0)):this._repeatDelay},_.yoyo=function(t){return arguments.length?(this._yoyo=t,this):this._yoyo},_.currentLabel=function(t){return arguments.length?this.seek(t,!0):this.getLabelBefore(this._time+1e-8)},s},!0),function(){var t=180/Math.PI,e=[],i=[],s=[],r={},n=_gsScope._gsDefine.globals,a=function(t,e,i,s){this.a=t,this.b=e,this.c=i,this.d=s,this.da=s-t,this.ca=i-t,this.ba=e-t},o=",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",h=function(t,e,i,s){var r={a:t},n={},a={},o={c:s},h=(t+e)/2,l=(e+i)/2,_=(i+s)/2,u=(h+l)/2,p=(l+_)/2,f=(p-u)/8;return r.b=h+(t-h)/4,n.b=u+f,r.c=n.a=(r.b+n.b)/2,n.c=a.a=(u+p)/2,a.b=p-f,o.b=_+(s-_)/4,a.c=o.a=(a.b+o.b)/2,[r,n,a,o]},l=function(t,r,n,a,o){var l,_,u,p,f,c,m,d,g,v,y,T,w,x=t.length-1,b=0,P=t[0].a;for(l=0;x>l;l++)f=t[b],_=f.a,u=f.d,p=t[b+1].d,o?(y=e[l],T=i[l],w=.25*(T+y)*r/(a?.5:s[l]||.5),c=u-(u-_)*(a?.5*r:0!==y?w/y:0),m=u+(p-u)*(a?.5*r:0!==T?w/T:0),d=u-(c+((m-c)*(3*y/(y+T)+.5)/4||0))):(c=u-.5*(u-_)*r,m=u+.5*(p-u)*r,d=u-(c+m)/2),c+=d,m+=d,f.c=g=c,f.b=0!==l?P:P=f.a+.6*(f.c-f.a),f.da=u-_,f.ca=g-_,f.ba=P-_,n?(v=h(_,P,g,u),t.splice(b,1,v[0],v[1],v[2],v[3]),b+=4):b++,P=m;f=t[b],f.b=P,f.c=P+.4*(f.d-P),f.da=f.d-f.a,f.ca=f.c-f.a,f.ba=P-f.a,n&&(v=h(f.a,P,f.c,f.d),t.splice(b,1,v[0],v[1],v[2],v[3]))},_=function(t,s,r,n){var o,h,l,_,u,p,f=[];if(n)for(t=[n].concat(t),h=t.length;--h>-1;)"string"==typeof(p=t[h][s])&&"="===p.charAt(1)&&(t[h][s]=n[s]+Number(p.charAt(0)+p.substr(2)));if(o=t.length-2,0>o)return f[0]=new a(t[0][s],0,0,t[-1>o?0:1][s]),f;for(h=0;o>h;h++)l=t[h][s],_=t[h+1][s],f[h]=new a(l,0,0,_),r&&(u=t[h+2][s],e[h]=(e[h]||0)+(_-l)*(_-l),i[h]=(i[h]||0)+(u-_)*(u-_));return f[h]=new a(t[h][s],0,0,t[h+1][s]),f},u=function(t,n,a,h,u,p){var f,c,m,d,g,v,y,T,w={},x=[],b=p||t[0];u="string"==typeof u?","+u+",":o,null==n&&(n=1);for(c in t[0])x.push(c);if(t.length>1){for(T=t[t.length-1],y=!0,f=x.length;--f>-1;)if(c=x[f],Math.abs(b[c]-T[c])>.05){y=!1;break}y&&(t=t.concat(),p&&t.unshift(p),t.push(t[1]),p=t[t.length-3])}for(e.length=i.length=s.length=0,f=x.length;--f>-1;)c=x[f],r[c]=-1!==u.indexOf(","+c+","),w[c]=_(t,c,r[c],p);for(f=e.length;--f>-1;)e[f]=Math.sqrt(e[f]),i[f]=Math.sqrt(i[f]);if(!h){for(f=x.length;--f>-1;)if(r[c])for(m=w[x[f]],v=m.length-1,d=0;v>d;d++)g=m[d+1].da/i[d]+m[d].da/e[d],s[d]=(s[d]||0)+g*g;for(f=s.length;--f>-1;)s[f]=Math.sqrt(s[f])}for(f=x.length,d=a?4:1;--f>-1;)c=x[f],m=w[c],l(m,n,a,h,r[c]),y&&(m.splice(0,d),m.splice(m.length-d,d));return w},p=function(t,e,i){e=e||"soft";var s,r,n,o,h,l,_,u,p,f,c,m={},d="cubic"===e?3:2,g="soft"===e,v=[];if(g&&i&&(t=[i].concat(t)),null==t||d+1>t.length)throw"invalid Bezier data";for(p in t[0])v.push(p);for(l=v.length;--l>-1;){for(p=v[l],m[p]=h=[],f=0,u=t.length,_=0;u>_;_++)s=null==i?t[_][p]:"string"==typeof(c=t[_][p])&&"="===c.charAt(1)?i[p]+Number(c.charAt(0)+c.substr(2)):Number(c),g&&_>1&&u-1>_&&(h[f++]=(s+h[f-2])/2),h[f++]=s;for(u=f-d+1,f=0,_=0;u>_;_+=d)s=h[_],r=h[_+1],n=h[_+2],o=2===d?0:h[_+3],h[f++]=c=3===d?new a(s,r,n,o):new a(s,(2*r+s)/3,(2*r+n)/3,n);h.length=f}return m},f=function(t,e,i){for(var s,r,n,a,o,h,l,_,u,p,f,c=1/i,m=t.length;--m>-1;)for(p=t[m],n=p.a,a=p.d-n,o=p.c-n,h=p.b-n,s=r=0,_=1;i>=_;_++)l=c*_,u=1-l,s=r-(r=(l*l*a+3*u*(l*o+u*h))*l),f=m*i+_-1,e[f]=(e[f]||0)+s*s},c=function(t,e){e=e>>0||6;var i,s,r,n,a=[],o=[],h=0,l=0,_=e-1,u=[],p=[];for(i in t)f(t[i],a,e);for(r=a.length,s=0;r>s;s++)h+=Math.sqrt(a[s]),n=s%e,p[n]=h,n===_&&(l+=h,n=s/e>>0,u[n]=p,o[n]=l,h=0,p=[]);return{length:l,lengths:o,segments:u}},m=_gsScope._gsDefine.plugin({propName:"bezier",priority:-1,version:"1.3.4",API:2,global:!0,init:function(t,e,i){this._target=t,e instanceof Array&&(e={values:e}),this._func={},this._round={},this._props=[],this._timeRes=null==e.timeResolution?6:parseInt(e.timeResolution,10);var s,r,n,a,o,h=e.values||[],l={},_=h[0],f=e.autoRotate||i.vars.orientToBezier;this._autoRotate=f?f instanceof Array?f:[["x","y","rotation",f===!0?0:Number(f)||0]]:null;for(s in _)this._props.push(s);for(n=this._props.length;--n>-1;)s=this._props[n],this._overwriteProps.push(s),r=this._func[s]="function"==typeof t[s],l[s]=r?t[s.indexOf("set")||"function"!=typeof t["get"+s.substr(3)]?s:"get"+s.substr(3)]():parseFloat(t[s]),o||l[s]!==h[0][s]&&(o=l);if(this._beziers="cubic"!==e.type&&"quadratic"!==e.type&&"soft"!==e.type?u(h,isNaN(e.curviness)?1:e.curviness,!1,"thruBasic"===e.type,e.correlate,o):p(h,e.type,l),this._segCount=this._beziers[s].length,this._timeRes){var m=c(this._beziers,this._timeRes);this._length=m.length,this._lengths=m.lengths,this._segments=m.segments,this._l1=this._li=this._s1=this._si=0,this._l2=this._lengths[0],this._curSeg=this._segments[0],this._s2=this._curSeg[0],this._prec=1/this._curSeg.length}if(f=this._autoRotate)for(this._initialRotations=[],f[0]instanceof Array||(this._autoRotate=f=[f]),n=f.length;--n>-1;){for(a=0;3>a;a++)s=f[n][a],this._func[s]="function"==typeof t[s]?t[s.indexOf("set")||"function"!=typeof t["get"+s.substr(3)]?s:"get"+s.substr(3)]:!1;
1726s=f[n][2],this._initialRotations[n]=this._func[s]?this._func[s].call(this._target):this._target[s]}return this._startRatio=i.vars.runBackwards?1:0,!0},set:function(e){var i,s,r,n,a,o,h,l,_,u,p=this._segCount,f=this._func,c=this._target,m=e!==this._startRatio;if(this._timeRes){if(_=this._lengths,u=this._curSeg,e*=this._length,r=this._li,e>this._l2&&p-1>r){for(l=p-1;l>r&&e>=(this._l2=_[++r]););this._l1=_[r-1],this._li=r,this._curSeg=u=this._segments[r],this._s2=u[this._s1=this._si=0]}else if(this._l1>e&&r>0){for(;r>0&&(this._l1=_[--r])>=e;);0===r&&this._l1>e?this._l1=0:r++,this._l2=_[r],this._li=r,this._curSeg=u=this._segments[r],this._s1=u[(this._si=u.length-1)-1]||0,this._s2=u[this._si]}if(i=r,e-=this._l1,r=this._si,e>this._s2&&u.length-1>r){for(l=u.length-1;l>r&&e>=(this._s2=u[++r]););this._s1=u[r-1],this._si=r}else if(this._s1>e&&r>0){for(;r>0&&(this._s1=u[--r])>=e;);0===r&&this._s1>e?this._s1=0:r++,this._s2=u[r],this._si=r}o=(r+(e-this._s1)/(this._s2-this._s1))*this._prec}else i=0>e?0:e>=1?p-1:p*e>>0,o=(e-i*(1/p))*p;for(s=1-o,r=this._props.length;--r>-1;)n=this._props[r],a=this._beziers[n][i],h=(o*o*a.da+3*s*(o*a.ca+s*a.ba))*o+a.a,this._round[n]&&(h=Math.round(h)),f[n]?c[n](h):c[n]=h;if(this._autoRotate){var d,g,v,y,T,w,x,b=this._autoRotate;for(r=b.length;--r>-1;)n=b[r][2],w=b[r][3]||0,x=b[r][4]===!0?1:t,a=this._beziers[b[r][0]],d=this._beziers[b[r][1]],a&&d&&(a=a[i],d=d[i],g=a.a+(a.b-a.a)*o,y=a.b+(a.c-a.b)*o,g+=(y-g)*o,y+=(a.c+(a.d-a.c)*o-y)*o,v=d.a+(d.b-d.a)*o,T=d.b+(d.c-d.b)*o,v+=(T-v)*o,T+=(d.c+(d.d-d.c)*o-T)*o,h=m?Math.atan2(T-v,y-g)*x+w:this._initialRotations[r],f[n]?c[n](h):c[n]=h)}}}),d=m.prototype;m.bezierThrough=u,m.cubicToQuadratic=h,m._autoCSS=!0,m.quadraticToCubic=function(t,e,i){return new a(t,(2*e+t)/3,(2*e+i)/3,i)},m._cssRegister=function(){var t=n.CSSPlugin;if(t){var e=t._internals,i=e._parseToProxy,s=e._setPluginRatio,r=e.CSSPropTween;e._registerComplexSpecialProp("bezier",{parser:function(t,e,n,a,o,h){e instanceof Array&&(e={values:e}),h=new m;var l,_,u,p=e.values,f=p.length-1,c=[],d={};if(0>f)return o;for(l=0;f>=l;l++)u=i(t,p[l],a,o,h,f!==l),c[l]=u.end;for(_ in e)d[_]=e[_];return d.values=c,o=new r(t,"bezier",0,0,u.pt,2),o.data=u,o.plugin=h,o.setRatio=s,0===d.autoRotate&&(d.autoRotate=!0),!d.autoRotate||d.autoRotate instanceof Array||(l=d.autoRotate===!0?0:Number(d.autoRotate),d.autoRotate=null!=u.end.left?[["left","top","rotation",l,!1]]:null!=u.end.x?[["x","y","rotation",l,!1]]:!1),d.autoRotate&&(a._transform||a._enableTransforms(!1),u.autoRotate=a._target._gsTransform),h._onInitTween(u.proxy,d,a._tween),o}})}},d._roundProps=function(t,e){for(var i=this._overwriteProps,s=i.length;--s>-1;)(t[i[s]]||t.bezier||t.bezierThrough)&&(this._round[i[s]]=e)},d._kill=function(t){var e,i,s=this._props;for(e in this._beziers)if(e in t)for(delete this._beziers[e],delete this._func[e],i=s.length;--i>-1;)s[i]===e&&s.splice(i,1);return this._super._kill.call(this,t)}}(),_gsScope._gsDefine("plugins.CSSPlugin",["plugins.TweenPlugin","TweenLite"],function(t,e){var i,s,r,n,a=function(){t.call(this,"css"),this._overwriteProps.length=0,this.setRatio=a.prototype.setRatio},o=_gsScope._gsDefine.globals,h={},l=a.prototype=new t("css");l.constructor=a,a.version="1.16.0",a.API=2,a.defaultTransformPerspective=0,a.defaultSkewType="compensated",l="px",a.suffixMap={top:l,right:l,bottom:l,left:l,width:l,height:l,fontSize:l,padding:l,margin:l,perspective:l,lineHeight:""};var _,u,p,f,c,m,d=/(?:\d|\-\d|\.\d|\-\.\d)+/g,g=/(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,v=/(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi,y=/(?![+-]?\d*\.?\d+|[+-]|e[+-]\d+)[^0-9]/g,T=/(?:\d|\-|\+|=|#|\.)*/g,w=/opacity *= *([^)]*)/i,x=/opacity:([^;]*)/i,b=/alpha\(opacity *=.+?\)/i,P=/^(rgb|hsl)/,S=/([A-Z])/g,k=/-([a-z])/gi,R=/(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi,A=function(t,e){return e.toUpperCase()},O=/(?:Left|Right|Width)/i,C=/(M11|M12|M21|M22)=[\d\-\.e]+/gi,D=/progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,M=/,(?=[^\)]*(?:\(|$))/gi,z=Math.PI/180,I=180/Math.PI,F={},E=document,N=function(t){return E.createElementNS?E.createElementNS("http://www.w3.org/1999/xhtml",t):E.createElement(t)},L=N("div"),X=N("img"),U=a._internals={_specialProps:h},Y=navigator.userAgent,j=function(){var t=Y.indexOf("Android"),e=N("a");return p=-1!==Y.indexOf("Safari")&&-1===Y.indexOf("Chrome")&&(-1===t||Number(Y.substr(t+8,1))>3),c=p&&6>Number(Y.substr(Y.indexOf("Version/")+8,1)),f=-1!==Y.indexOf("Firefox"),(/MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(Y)||/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(Y))&&(m=parseFloat(RegExp.$1)),e?(e.style.cssText="top:1px;opacity:.55;",/^0.55/.test(e.style.opacity)):!1}(),B=function(t){return w.test("string"==typeof t?t:(t.currentStyle?t.currentStyle.filter:t.style.filter)||"")?parseFloat(RegExp.$1)/100:1},q=function(t){window.console&&console.log(t)},V="",G="",W=function(t,e){e=e||L;var i,s,r=e.style;if(void 0!==r[t])return t;for(t=t.charAt(0).toUpperCase()+t.substr(1),i=["O","Moz","ms","Ms","Webkit"],s=5;--s>-1&&void 0===r[i[s]+t];);return s>=0?(G=3===s?"ms":i[s],V="-"+G.toLowerCase()+"-",G+t):null},Z=E.defaultView?E.defaultView.getComputedStyle:function(){},Q=a.getStyle=function(t,e,i,s,r){var n;return j||"opacity"!==e?(!s&&t.style[e]?n=t.style[e]:(i=i||Z(t))?n=i[e]||i.getPropertyValue(e)||i.getPropertyValue(e.replace(S,"-$1").toLowerCase()):t.currentStyle&&(n=t.currentStyle[e]),null==r||n&&"none"!==n&&"auto"!==n&&"auto auto"!==n?n:r):B(t)},$=U.convertToPixels=function(t,i,s,r,n){if("px"===r||!r)return s;if("auto"===r||!s)return 0;var o,h,l,_=O.test(i),u=t,p=L.style,f=0>s;if(f&&(s=-s),"%"===r&&-1!==i.indexOf("border"))o=s/100*(_?t.clientWidth:t.clientHeight);else{if(p.cssText="border:0 solid red;position:"+Q(t,"position")+";line-height:0;","%"!==r&&u.appendChild)p[_?"borderLeftWidth":"borderTopWidth"]=s+r;else{if(u=t.parentNode||E.body,h=u._gsCache,l=e.ticker.frame,h&&_&&h.time===l)return h.width*s/100;p[_?"width":"height"]=s+r}u.appendChild(L),o=parseFloat(L[_?"offsetWidth":"offsetHeight"]),u.removeChild(L),_&&"%"===r&&a.cacheWidths!==!1&&(h=u._gsCache=u._gsCache||{},h.time=l,h.width=100*(o/s)),0!==o||n||(o=$(t,i,s,r,!0))}return f?-o:o},H=U.calculateOffset=function(t,e,i){if("absolute"!==Q(t,"position",i))return 0;var s="left"===e?"Left":"Top",r=Q(t,"margin"+s,i);return t["offset"+s]-($(t,e,parseFloat(r),r.replace(T,""))||0)},K=function(t,e){var i,s,r,n={};if(e=e||Z(t,null))if(i=e.length)for(;--i>-1;)r=e[i],(-1===r.indexOf("-transform")||be===r)&&(n[r.replace(k,A)]=e.getPropertyValue(r));else for(i in e)(-1===i.indexOf("Transform")||xe===i)&&(n[i]=e[i]);else if(e=t.currentStyle||t.style)for(i in e)"string"==typeof i&&void 0===n[i]&&(n[i.replace(k,A)]=e[i]);return j||(n.opacity=B(t)),s=Me(t,e,!1),n.rotation=s.rotation,n.skewX=s.skewX,n.scaleX=s.scaleX,n.scaleY=s.scaleY,n.x=s.x,n.y=s.y,Se&&(n.z=s.z,n.rotationX=s.rotationX,n.rotationY=s.rotationY,n.scaleZ=s.scaleZ),n.filters&&delete n.filters,n},J=function(t,e,i,s,r){var n,a,o,h={},l=t.style;for(a in i)"cssText"!==a&&"length"!==a&&isNaN(a)&&(e[a]!==(n=i[a])||r&&r[a])&&-1===a.indexOf("Origin")&&("number"==typeof n||"string"==typeof n)&&(h[a]="auto"!==n||"left"!==a&&"top"!==a?""!==n&&"auto"!==n&&"none"!==n||"string"!=typeof e[a]||""===e[a].replace(y,"")?n:0:H(t,a),void 0!==l[a]&&(o=new fe(l,a,l[a
1726],o)));if(s)for(a in s)"className"!==a&&(h[a]=s[a]);return{difs:h,firstMPT:o}},te={width:["Left","Right"],height:["Top","Bottom"]},ee=["marginLeft","marginRight","marginTop","marginBottom"],ie=function(t,e,i){var s=parseFloat("width"===e?t.offsetWidth:t.offsetHeight),r=te[e],n=r.length;for(i=i||Z(t,null);--n>-1;)s-=parseFloat(Q(t,"padding"+r[n],i,!0))||0,s-=parseFloat(Q(t,"border"+r[n]+"Width",i,!0))||0;return s},se=function(t,e){(null==t||""===t||"auto"===t||"auto auto"===t)&&(t="0 0");var i=t.split(" "),s=-1!==t.indexOf("left")?"0%":-1!==t.indexOf("right")?"100%":i[0],r=-1!==t.indexOf("top")?"0%":-1!==t.indexOf("bottom")?"100%":i[1];return null==r?r="center"===s?"50%":"0":"center"===r&&(r="50%"),("center"===s||isNaN(parseFloat(s))&&-1===(s+"").indexOf("="))&&(s="50%"),e&&(e.oxp=-1!==s.indexOf("%"),e.oyp=-1!==r.indexOf("%"),e.oxr="="===s.charAt(1),e.oyr="="===r.charAt(1),e.ox=parseFloat(s.replace(y,"")),e.oy=parseFloat(r.replace(y,""))),s+" "+r+(i.length>2?" "+i[2]:"")},re=function(t,e){return"string"==typeof t&&"="===t.charAt(1)?parseInt(t.charAt(0)+"1",10)*parseFloat(t.substr(2)):parseFloat(t)-parseFloat(e)},ne=function(t,e){return null==t?e:"string"==typeof t&&"="===t.charAt(1)?parseInt(t.charAt(0)+"1",10)*parseFloat(t.substr(2))+e:parseFloat(t)},ae=function(t,e,i,s){var r,n,a,o,h,l=1e-6;return null==t?o=e:"number"==typeof t?o=t:(r=360,n=t.split("_"),h="="===t.charAt(1),a=(h?parseInt(t.charAt(0)+"1",10)*parseFloat(n[0].substr(2)):parseFloat(n[0]))*(-1===t.indexOf("rad")?1:I)-(h?0:e),n.length&&(s&&(s[i]=e+a),-1!==t.indexOf("short")&&(a%=r,a!==a%(r/2)&&(a=0>a?a+r:a-r)),-1!==t.indexOf("_cw")&&0>a?a=(a+9999999999*r)%r-(0|a/r)*r:-1!==t.indexOf("ccw")&&a>0&&(a=(a-9999999999*r)%r-(0|a/r)*r)),o=e+a),l>o&&o>-l&&(o=0),o},oe={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},he=function(t,e,i){return t=0>t?t+1:t>1?t-1:t,0|255*(1>6*t?e+6*(i-e)*t:.5>t?i:2>3*t?e+6*(i-e)*(2/3-t):e)+.5},le=a.parseColor=function(t){var e,i,s,r,n,a;return t&&""!==t?"number"==typeof t?[t>>16,255&t>>8,255&t]:(","===t.charAt(t.length-1)&&(t=t.substr(0,t.length-1)),oe[t]?oe[t]:"#"===t.charAt(0)?(4===t.length&&(e=t.charAt(1),i=t.charAt(2),s=t.charAt(3),t="#"+e+e+i+i+s+s),t=parseInt(t.substr(1),16),[t>>16,255&t>>8,255&t]):"hsl"===t.substr(0,3)?(t=t.match(d),r=Number(t[0])%360/360,n=Number(t[1])/100,a=Number(t[2])/100,i=.5>=a?a*(n+1):a+n-a*n,e=2*a-i,t.length>3&&(t[3]=Number(t[3])),t[0]=he(r+1/3,e,i),t[1]=he(r,e,i),t[2]=he(r-1/3,e,i),t):(t=t.match(d)||oe.transparent,t[0]=Number(t[0]),t[1]=Number(t[1]),t[2]=Number(t[2]),t.length>3&&(t[3]=Number(t[3])),t)):oe.black},_e="(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b";for(l in oe)_e+="|"+l+"\\b";_e=RegExp(_e+")","gi");var ue=function(t,e,i,s){if(null==t)return function(t){return t};var r,n=e?(t.match(_e)||[""])[0]:"",a=t.split(n).join("").match(v)||[],o=t.substr(0,t.indexOf(a[0])),h=")"===t.charAt(t.length-1)?")":"",l=-1!==t.indexOf(" ")?" ":",",_=a.length,u=_>0?a[0].replace(d,""):"";return _?r=e?function(t){var e,p,f,c;if("number"==typeof t)t+=u;else if(s&&M.test(t)){for(c=t.replace(M,"|").split("|"),f=0;c.length>f;f++)c[f]=r(c[f]);return c.join(",")}if(e=(t.match(_e)||[n])[0],p=t.split(e).join("").match(v)||[],f=p.length,_>f--)for(;_>++f;)p[f]=i?p[0|(f-1)/2]:a[f];return o+p.join(l)+l+e+h+(-1!==t.indexOf("inset")?" inset":"")}:function(t){var e,n,p;if("number"==typeof t)t+=u;else if(s&&M.test(t)){for(n=t.replace(M,"|").split("|"),p=0;n.length>p;p++)n[p]=r(n[p]);return n.join(",")}if(e=t.match(v)||[],p=e.length,_>p--)for(;_>++p;)e[p]=i?e[0|(p-1)/2]:a[p];return o+e.join(l)+h}:function(t){return t}},pe=function(t){return t=t.split(","),function(e,i,s,r,n,a,o){var h,l=(i+"").split(" ");for(o={},h=0;4>h;h++)o[t[h]]=l[h]=l[h]||l[(h-1)/2>>0];return r.parse(e,o,n,a)}},fe=(U._setPluginRatio=function(t){this.plugin.setRatio(t);for(var e,i,s,r,n=this.data,a=n.proxy,o=n.firstMPT,h=1e-6;o;
vendor: 4,282 bytes, line 1726
1726)e=a[o.v],o.r?e=Math.round(e):h>e&&e>-h&&(e=0),o.t[o.p]=e,o=o._next;if(n.autoRotate&&(n.autoRotate.rotation=a.rotation),1===t)for(o=n.firstMPT;o;){if(i=o.t,i.type){if(1===i.type){for(r=i.xs0+i.s+i.xs1,s=1;i.l>s;s++)r+=i["xn"+s]+i["xs"+(s+1)];i.e=r}}else i.e=i.s+i.xs0;o=o._next}},function(t,e,i,s,r){this.t=t,this.p=e,this.v=i,this.r=r,s&&(s._prev=this,this._next=s)}),ce=(U._parseToProxy=function(t,e,i,s,r,n){var a,o,h,l,_,u=s,p={},f={},c=i._transform,m=F;for(i._transform=null,F=e,s=_=i.parse(t,e,s,r),F=m,n&&(i._transform=c,u&&(u._prev=null,u._prev&&(u._prev._next=null)));s&&s!==u;){if(1>=s.type&&(o=s.p,f[o]=s.s+s.c,p[o]=s.s,n||(l=new fe(s,"s",o,l,s.r),s.c=0),1===s.type))for(a=s.l;--a>0;)h="xn"+a,o=s.p+"_"+h,f[o]=s.data[h],p[o]=s[h],n||(l=new fe(s,h,o,l,s.rxp[h]));s=s._next}return{proxy:p,end:f,firstMPT:l,pt:_}},U.CSSPropTween=function(t,e,s,r,a,o,h,l,_,u,p){this.t=t,this.p=e,this.s=s,this.c=r,this.n=h||e,t instanceof ce||n.push(this.n),this.r=l,this.type=o||0,_&&(this.pr=_,i=!0),this.b=void 0===u?s:u,this.e=void 0===p?s+r:p,a&&(this._next=a,a._prev=this)}),me=a.parseComplex=function(t,e,i,s,r,n,a,o,h,l){i=i||n||"",a=new ce(t,e,0,0,a,l?2:1,null,!1,o,i,s),s+="";var u,p,f,c,m,v,y,T,w,x,b,S,k=i.split(", ").join(",").split(" "),R=s.split(", ").join(",").split(" "),A=k.length,O=_!==!1;for((-1!==s.indexOf(",")||-1!==i.indexOf(","))&&(k=k.join(" ").replace(M,", ").split(" "),R=R.join(" ").replace(M,", ").split(" "),A=k.length),A!==R.length&&(k=(n||"").split(" "),A=k.length),a.plugin=h,a.setRatio=l,u=0;A>u;u++)if(c=k[u],m=R[u],T=parseFloat(c),T||0===T)a.appendXtra("",T,re(m,T),m.replace(g,""),O&&-1!==m.indexOf("px"),!0);else if(r&&("#"===c.charAt(0)||oe[c]||P.test(c)))S=","===m.charAt(m.length-1)?"),":")",c=le(c),m=le(m),w=c.length+m.length>6,w&&!j&&0===m[3]?(a["xs"+a.l]+=a.l?" transparent":"transparent",a.e=a.e.split(R[u]).join("transparent")):(j||(w=!1),a.appendXtra(w?"rgba(":"rgb(",c[0],m[0]-c[0],",",!0,!0).appendXtra("",c[1],m[1]-c[1],",",!0).appendXtra("",c[2],m[2]-c[2],w?",":S,!0),w&&(c=4>c.length?1:c[3],a.appendXtra("",c,(4>m.length?1:m[3])-c,S,!1)));else if(v=c.match(d)){if(y=m.match(g),!y||y.length!==v.length)return a;for(f=0,p=0;v.length>p;p++)b=v[p],x=c.indexOf(b,f),a.appendXtra(c.substr(f,x-f),Number(b),re(y[p],b),"",O&&"px"===c.substr(x+b.length,2),0===p),f=x+b.length;a["xs"+a.l]+=c.substr(f)}else a["xs"+a.l]+=a.l?" "+c:c;if(-1!==s.indexOf("=")&&a.data){for(S=a.xs0+a.data.s,u=1;a.l>u;u++)S+=a["xs"+u]+a.data["xn"+u];a.e=S+a["xs"+u]}return a.l||(a.type=-1,a.xs0=a.e),a.xfirst||a},de=9;for(l=ce.prototype,l.l=l.pr=0;--de>0;)l["xn"+de]=0,l["xs"+de]="";l.xs0="",l._next=l._prev=l.xfirst=l.data=l.plugin=l.setRatio=l.rxp=null,l.appendXtra=function(t,e,i,s,r,n){var a=this,o=a.l;return a["xs"+o]+=n&&o?" "+t:t||"",i||0===o||a.plugin?(a.l++,a.type=a.setRatio?2:1,a["xs"+a.l]=s||"",o>0?(a.data["xn"+o]=e+i,a.rxp["xn"+o]=r,a["xn"+o]=e,a.plugin||(a.xfirst=new ce(a,"xn"+o,e,i,a.xfirst||a,0,a.n,r,a.pr),a.xfirst.xs0=0),a):(a.data={s:e+i},a.rxp={},a.s=e,a.c=i,a.r=r,a)):(a["xs"+o]+=e+(s||""),a)};var ge=function(t,e){e=e||{},this.p=e.prefix?W(t)||t:t,h[t]=h[this.p]=this,this.format=e.formatter||ue(e.defaultValue,e.color,e.collapsible,e.multi),e.parser&&(this.parse=e.parser),this.clrs=e.color,this.multi=e.multi,this.keyword=e.keyword,this.dflt=e.defaultValue,this.pr=e.priority||0},ve=U._registerComplexSpecialProp=function(t,e,i){"object"!=typeof e&&(e={parser:i});var s,r,n=t.split(","),a=e.defaultValue;for(i=i||[a],s=0;n.length>s;s++)e.prefix=0===s&&e.prefix,e.defaultValue=i[s]||a,r=new ge(n[s],e)},ye=function(t){if(!h[t]){var e=t.charAt(0).toUpperCase()+t.substr(1)+"Plugin";ve(t,{parser:function(t,i,s,r,n,a,l){var _=o.com.greensock.plugins[e];return _?(_._cssRegister(),h[s].parse(t,i,s,r,n,a,l)):(q("Error: "+e+" js file not loaded."),n)}})}};l=ge.prototype,l.parseComplex=function(t,e,i,s,r,n){var a,o,h,l,_,u,p=this.keyword;if(this.multi&&(M.test(i)||M.test(e)?(o=e.replace(M,"|").split("|"),h=i.replace(M,"|").split("|")):p&&(o=[e],h=[i])),h){for(l=h.length>o.length?h.length:o.length,a=0;l>a;a++)e=o[a]=o[a]||this.dflt,i=h[a]=h[a]||this.dflt,p&&(_=e.indexOf(p),u=i.indexOf(p),_!==u&&(-1===u?o[a]=o[a].split(p).join(""):-1===_&&(o[a]+=" "+p)));e=o.join(", "),i=h.join(", ")}return me(t,this.p,e,i,this.clrs,this.dflt,s,this.pr,r,n)}
1726,l.parse=function(t,e,i,s,n,a){return this.parseComplex(t.style,this.format(Q(t,this.p,r,!1,this.dflt)),this.format(e),n,a)},a.registerSpecialProp=function(t,e,i){ve(t,{parser:function(t,s,r,n,a,o){var h=new ce(t,r,0,0,a,2,r,!1,i);return h.plugin=o,h.setRatio=e(t,s,n._tween,r),h},priority:i})},a.useSVGTransformAttr=p;var Te,we="scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective,xPercent,yPercent".split(","),xe=W("transform"),be=V+"transform",Pe=W("transformOrigin"),Se=null!==W("perspective"),ke=U.Transform=function(){this.perspective=parseFloat(a.defaultTransformPerspective)||0,this.force3D=a.defaultForce3D!==!1&&Se?a.defaultForce3D||"auto":!1},Re=window.SVGElement,Ae=function(t,e,i){var s,r=E.createElementNS("http://www.w3.org/2000/svg",t),n=/([a-z])([A-Z])/g;for(s in i)r.setAttributeNS(null,s.replace(n,"$1-$2").toLowerCase(),i[s]);return e.appendChild(r),r},Oe=E.documentElement,Ce=function(){var t,e,i,s=m||/Android/i.test(Y)&&!window.chrome;return E.createElementNS&&!s&&(t=Ae("svg",Oe),e=Ae("rect",t,{width:100,height:50,x:100}),i=e.getBoundingClientRect().width,e.style[Pe]="50% 50%",e.style[xe]="scaleX(0.5)",s=i===e.getBoundingClientRect().width&&!(f&&Se),Oe.removeChild(t)),s}(),De=function(t,e,i,s){var r,n;s&&(n=s.split(" ")).length||(r=t.getBBox(),e=se(e).split(" "),n=[(-1!==e[0].indexOf("%")?parseFloat(e[0])/100*r.width:parseFloat(e[0]))+r.x,(-1!==e[1].indexOf("%")?parseFloat(e[1])/100*r.height:parseFloat(e[1]))+r.y]),i.xOrigin=parseFloat(n[0]),i.yOrigin=parseFloat(n[1]),t.setAttribute("data-svg-origin",n.join(" "))},Me=U.getTransform=function(t,e,i,s){if(t._gsTransform&&i&&!s)return t._gsTransform;var n,o,h,l,_,u,p,f,c,m,d=i?t._gsTransform||new ke:new ke,g=0>d.scaleX,v=2e-5,y=1e5,T=Se?parseFloat(Q(t,Pe,e,!1,"0 0 0").split(" ")[2])||d.zOrigin||0:0,w=parseFloat(a.defaultTransformPerspective)||0;if(xe?o=Q(t,be,e,!0):t.currentStyle&&(o=t.currentStyle.filter.match(C),o=o&&4===o.length?[o[0].substr(4),Number(o[2].substr(4)),Number(o[1].substr(4)),o[3].substr(4),d.x||0,d.y||0].join(","):""),n=!o||"none"===o||"matrix(1, 0, 0, 1, 0, 0)"===o,d.svg=!!(Re&&"function"==typeof t.getBBox&&t.getCTM&&(!t.parentNode||t.parentNode.getBBox&&t.parentNode.getCTM)),d.svg&&(n&&-1!==(t.style[xe]+"").indexOf("matrix")&&(o=t.style[xe],n=!1),De(t,Q(t,Pe,r,!1,"50% 50%")+"",d,t.getAttribute("data-svg-origin")),Te=a.useSVGTransformAttr||Ce,h=t.getAttribute("transform"),n&&h&&-1!==h.indexOf("matrix")&&(o=h,n=0)),!n){for(h=(o||"").match(/(?:\-|\b)[\d\-\.e]+\b/gi)||[],l=h.length;--l>-1;)_=Number(h[l]),h[l]=(u=_-(_|=0))?(0|u*y+(0>u?-.5:.5))/y+_:_;if(16===h.length){var x,b,P,S,k,R=h[0],A=h[1],O=h[2],D=h[3],M=h[4],z=h[5],F=h[6],E=h[7],N=h[8],L=h[9],X=h[10],U=h[12],Y=h[13],j=h[14],B=h[11],q=Math.atan2(F,X);d.zOrigin&&(j=-d.zOrigin,U=N*j-h[12],Y=L*j-h[13],j=X*j+d.zOrigin-h[14]),d.rotationX=q*I,q&&(S=Math.cos(-q),k=Math.sin(-q),x=M*S+N*k,b=z*S+L*k,P=F*S+X*k,N=M*-k+N*S,L=z*-k+L*S,X=F*-k+X*S,B=E*-k+B*S,M=x,z=b,F=P),q=Math.atan2(N,X),d.rotationY=q*I,q&&(S=Math.cos(-q),k=Math.sin(-q),x=R*S-N*k,b=A*S-L*k,P=O*S-X*k,L=A*k+L*S,X=O*k+X*S,B=D*k+B*S,R=x,A=b,O=P),q=Math.atan2(A,R),d.rotation=q*I,q&&(S=Math.cos(-q),k=Math.sin(-q),R=R*S+M*k,b=A*S+z*k,z=A*-k+z*S,F=O*-k+F*S,A=b),d.rotationX&&Math.abs(d.rotationX)+Math.abs(d.rotation)>359.9&&(d.rotationX=d.rotation=0,d.rotationY+=180),d.scaleX=(0|Math.sqrt(R*R+A*A)*y+.5)/y,d.scaleY=(0|Math.sqrt(z*z+L*L)*y+.5)/y,d.scaleZ=(0|Math.sqrt(F*F+X*X)*y+.5)/y,d.skewX=0,d.perspective=B?1/(0>B?-B:B):0,d.x=U,d.y=Y,d.z=j,d.svg&&(d.x-=d.xOrigin-(d.xOrigin*R-d.yOrigin*M),d.y-=d.yOrigin-(d.yOrigin*A-d.xOrigin*z))}else if(!(Se&&!s&&h.length&&d.x===h[4]&&d.y===h[5]&&(d.rotationX||d.rotationY)||void 0!==d.x&&"none"===Q(t,"display",e))){var V=h.length>=6,G=V?h[0]:1,W=h[1]||0,Z=h[2]||0,$=V?h[3]:1;d.x=h[4]||0,d.y=h[5]||0,p=Math.sqrt(G*G+W*W),f=Math.sqrt($*$+Z*Z),c=G||W?Math.atan2(W,G)*I:d.rotation||0,m=Z||$?Math.atan2(Z,$)*I+c:d.skewX||0,Math.abs(m)>90&&270>Math.abs(m)&&(g?(p*=-1,m+=0>=c?180:-180,c+=0>=c?180:-180):(f*=-1,m+=0>=m?180:-180)),d.scaleX=p,d.scaleY=f,d.rotation=c,d.skewX=m,Se&&(d.rotationX=d.rotationY=d.z=0,d.perspective=w,d.scaleZ=1),d.svg&&(d.x-=d.xOrigin-(d.xOrigin*G-d.yOrigin*W),d.y-=d.yOrigin-(d.yOrigin*$-d.xOrigin*Z))}d.zOrigin=T;for(l in d)v>d[l]&&d[l]>-v&&(d[l]=0)}return i&&(t._gsTransform=d,d.svg&&(Te&&t.style[xe]?Ne(t.style,xe):!Te&&t.getAttribute("transform")&&t.removeAttribute("transform"))),d},ze=function(t){var e,i,s=this.data,r=-s.rotation*z,n=r+s.skewX*z,a=1e5,o=(0|Math.cos(r)*s.scaleX*a)/a,h=(0|Math.sin(r)*s.scaleX*a)/a,l=(0|Math.sin(n)*-s.scaleY*a)/a,_=(0|Math.cos(n)*s.scaleY*a)/a,u=this.t.style,p=this.t.currentStyle;if(p){i=h,h=-l,l=-i,e=p.filter,u.filter="";var f,c,d=this.t.offsetWidth,g=this.t.offsetHeight,v="absolute"!==p.position,y="progid:DXImageTransform.Microsoft.Matrix(M11="+o+", M12="+h+", M21="+l+", M22="+_,x=s.x+d*s.xPercent/100,b=s.y+g*s.yPercent/100;if(null!=s.ox&&(f=(s.oxp?.01*d*s.ox:s.ox)-d/2,c=(s.oyp?.01*g*s.oy:s.oy)-g/2,x+=f-(f*o+c*h),b+=c-(f*l+c*_)),v?(f=d/2,c=g/2,y+=", Dx="+(f-(f*o+c*h)+x)+", Dy="+(c-(f*l+c*_)+b)+")"):y+=", sizingMethod='auto expand')",u.filter=-1!==e.indexOf("DXImageTransform.Microsoft.Matrix(")?e.replace(D,y):y+" "+e,(0===t||1===t)&&1===o&&0===h&&0===l&&1===_&&(v&&-1===y.indexOf("Dx=0, Dy=0")||w.test(e)&&100!==parseFloat(RegExp.$1)||-1===e.indexOf("gradient("&&e.indexOf("Alpha"))&&u.removeAttribute("filter")),!v){var P,S,k,R=8>m?1:-1;for(f=s.ieOffsetX||0,c=s.ieOffsetY||0,s.ieOffsetX=Math.round((d-((0>o?-o:o)*d+(0>h?-h:h)*g))/2+x),s.ieOffsetY=Math.round((g-((0>_?-_:_)*g+(0>
1726l?-l:l)*d))/2+b),de=0;4>de;de++)S=ee[de],P=p[S],i=-1!==P.indexOf("px")?parseFloat(P):$(this.t,S,parseFloat(P),P.replace(T,""))||0,k=i!==s[S]?2>de?-s.ieOffsetX:-s.ieOffsetY:2>de?f-s.ieOffsetX:c-s.ieOffsetY,u[S]=(s[S]=Math.round(i-k*(0===de||2===de?1:R)))+"px"}}},Ie=U.set3DTransformRatio=function(t){var e,i,s,r,n,a,o,h,l,_,u,p,c,m,d,g,v,y,T,w,x,b=this.data,P=this.t.style,S=b.rotation*z,k=b.scaleX,R=b.scaleY,A=b.scaleZ,O=b.x,C=b.y,D=b.z,M=b.perspective;if(!(1!==t&&0!==t&&b.force3D||b.force3D===!0||b.rotationY||b.rotationX||1!==A||M||D||this.tween._totalTime!==this.tween._totalDuration&&this.tween._totalTime))return Fe.call(this,t),void 0;if(f&&(m=1e-4,m>k&&k>-m&&(k=A=2e-5),m>R&&R>-m&&(R=A=2e-5),!M||b.z||b.rotationX||b.rotationY||(M=0)),S||b.skewX)d=e=Math.cos(S),g=r=Math.sin(S),b.skewX&&(S-=b.skewX*z,d=Math.cos(S),g=Math.sin(S),"simple"===b.skewType&&(v=Math.tan(b.skewX*z),v=Math.sqrt(1+v*v),d*=v,g*=v)),i=-g,n=d;else{if(!(b.rotationY||b.rotationX||1!==A||M||b.svg))return P[xe]=(b.xPercent||b.yPercent?"translate("+b.xPercent+"%,"+b.yPercent+"%) translate3d(":"translate3d(")+O+"px,"+C+"px,"+D+"px)"+(1!==k||1!==R?" scale("+k+","+R+")":""),void 0;e=n=1,i=r=0}l=1,s=a=o=h=_=u=0,p=M?-1/M:0,c=b.zOrigin,m=1e-6,w=",",x="0",S=b.rotationY*z,S&&(d=Math.cos(S),g=Math.sin(S),o=-g,_=p*-g,s=e*g,a=r*g,l=d,p*=d,e*=d,r*=d),S=b.rotationX*z,S&&(d=Math.cos(S),g=Math.sin(S),v=i*d+s*g,y=n*d+a*g,h=l*g,u=p*g,s=i*-g+s*d,a=n*-g+a*d,l*=d,p*=d,i=v,n=y),1!==A&&(s*=A,a*=A,l*=A,p*=A),1!==R&&(i*=R,n*=R,h*=R,u*=R),1!==k&&(e*=k,r*=k,o*=k,_*=k),(c||b.svg)&&(c&&(O+=s*-c,C+=a*-c,D+=l*-c+c),b.svg&&(O+=b.xOrigin-(b.xOrigin*e+b.yOrigin*i),C+=b.yOrigin-(b.xOrigin*r+b.yOrigin*n)),m>O&&O>-m&&(O=x),m>C&&C>-m&&(C=x),m>D&&D>-m&&(D=0)),T=b.xPercent||b.yPercent?"translate("+b.xPercent+"%,"+b.yPercent+"%) matrix3d(":"matrix3d(",T+=(m>e&&e>-m?x:e)+w+(m>r&&r>-m?x:r)+w+(m>o&&o>-m?x:o),T+=w+(m>_&&_>-m?x:_)+w+(m>i&&i>-m?x:i)+w+(m>n&&n>-m?x:n),b.rotationX||b.rotationY?(T+=w+(m>h&&h>-m?x:h)+w+(m>u&&u>-m?x:u)+w+(m>s&&s>-m?x:s),T+=w+(m>a&&a>-m?x:a)+w+(m>l&&l>-m?x:l)+w+(m>p&&p>-m?x:p)+w):T+=",0,0,0,0,1,0,",T+=O+w+C+w+D+w+(M?1+-D/M:1)+")",P[xe]=T},Fe=U.set2DTransformRatio=function(t){var e,i,s,r,n,a,o,h,l,_,u,p,f=this.data,c=this.t,m=c.style,d=f.x,g=f.y;return!(f.rotationX||f.rotationY||f.z||f.force3D===!0||"auto"===f.force3D&&1!==t&&0!==t)||f.svg&&Te||!Se?(r=f.scaleX,n=f.scaleY,f.rotation||f.skewX||f.svg?(e=f.rotation*z,i=f.skewX*z,s=1e5,a=Math.cos(e)*r,o=Math.sin(e)*r,h=Math.sin(e-i)*-n,l=Math.cos(e-i)*n,i&&"simple"===f.skewType&&(p=Math.tan(i),p=Math.sqrt(1+p*p),h*=p,l*=p),f.svg&&(d+=f.xOrigin-(f.xOrigin*a+f.yOrigin*h),g+=f.yOrigin-(f.xOrigin*o+f.yOrigin*l),u=1e-6,u>d&&d>-u&&(d=0),u>g&&g>-u&&(g=0)),_=(0|a*s)/s+","+(0|o*s)/s+","+(0|h*s)/s+","+(0|l*s)/s+","+d+","+g+")",f.svg&&Te?c.setAttribute("transform","matrix("+_):m[xe]=(f.xPercent||f.yPercent?"translate("+f.xPercent+"%,"+f.yPercent+"%) matrix(":"matrix(")+_):m[xe]=(f.xPercent||f.yPercent?"translate("+f.xPercent+"%,"+f.yPercent+"%) matrix(":"matrix(")+r+",0,0,"+n+","+d+","+g+")",void 0):(this.setRatio=Ie,Ie.call(this,t),void 0)};l=ke.prototype,l.x=l.y=l.z=l.skewX=l.skewY=l.rotation=l.rotationX=l.rotationY=l.zOrigin=l.xPercent=l.yPercent=0,l.scaleX=l.scaleY=l.scaleZ=1,ve("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,svgOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType,xPercent,yPercent",{parser:function(t,e,i,s,n,o,h){if(s._lastParsedTransform===h)return n;s._lastParsedTransform=h;var l,_,u,p,f,c,m,d=s._transform=Me(t,r,!0,h.parseTransform),g=t.style,v=1e-6,y=we.length,T=h,w={};if("string"==typeof T.transform&&xe)u=L.style,u[xe]=T.transform,u.display="block",u.position="absolute",E.body.appendChild(L),l=Me(L,null,!1),E.body.removeChild(L);else if("object"==typeof T){if(l={scaleX:ne(null!=T.scaleX?T.scaleX:T.scale,d.scaleX),scaleY:ne(null!=T.scaleY?T.scaleY:T.scale,d.scaleY),scaleZ:ne(T.scaleZ,d.scaleZ),x:ne(T.x,d.x),y:ne(T.y,d.y),z:ne(T.z,d.z),xPercent:ne(T.xPercent,d.xPercent),yPercent:ne(T.yPercent,d.yPercent),perspective:ne(T.transformPerspective,d.perspective)},m=T.directionalRotation,null!=m)if("object"==typeof m)for(u in m)T[u]=m[u];else T.rotation=m;"string"==typeof T.x&&-1!==T.x.indexOf("%")&&(l.x=0,l.xPercent=ne(T.x,d.xPercent)),"string"==typeof T.y&&-1!==T.y.indexOf("%")&&(l.y=0,l.yPercent=ne(T.y,d.yPercent)),l.rotation=ae("rotation"in T?T.rotation:"shortRotation"in T?T.shortRotation+"_short":"rotationZ"in T?T.rotationZ:d.rotation,d.rotation,"rotation",w),Se&&(l.rotationX=ae("rotationX"in T?T.rotationX:"shortRotationX"in T?T.shortRotationX+"_short":d.rotationX||0,d.rotationX,"rotationX",w),l.rotationY=ae("rotationY"
1726in T?T.rotationY:"shortRotationY"in T?T.shortRotationY+"_short":d.rotationY||0,d.rotationY,"rotationY",w)),l.skewX=null==T.skewX?d.skewX:ae(T.skewX,d.skewX),l.skewY=null==T.skewY?d.skewY:ae(T.skewY,d.skewY),(_=l.skewY-d.skewY)&&(l.skewX+=_,l.rotation+=_)}for(Se&&null!=T.force3D&&(d.force3D=T.force3D,c=!0),d.skewType=T.skewType||d.skewType||a.defaultSkewType,f=d.force3D||d.z||d.rotationX||d.rotationY||l.z||l.rotationX||l.rotationY||l.perspective,f||null==T.scale||(l.scaleZ=1);--y>-1;)i=we[y],p=l[i]-d[i],(p>v||-v>p||null!=T[i]||null!=F[i])&&(c=!0,n=new ce(d,i,d[i],p,n),i in w&&(n.e=w[i]),n.xs0=0,n.plugin=o,s._overwriteProps.push(n.n));return p=T.transformOrigin,d.svg&&(p||T.svgOrigin)&&(De(t,se(p),l,T.svgOrigin),n=new ce(d,"xOrigin",d.xOrigin,l.xOrigin-d.xOrigin,n,-1,"transformOrigin"),n.b=d.xOrigin,n.e=n.xs0=l.xOrigin,n=new ce(d,"yOrigin",d.yOrigin,l.yOrigin-d.yOrigin,n,-1,"transformOrigin"),n.b=d.yOrigin,n.e=n.xs0=l.yOrigin,p=Te?null:"0px 0px"),(p||Se&&f&&d.zOrigin)&&(xe?(c=!0,i=Pe,p=(p||Q(t,i,r,!1,"50% 50%"))+"",n=new ce(g,i,0,0,n,-1,"transformOrigin"),n.b=g[i],n.plugin=o,Se?(u=d.zOrigin,p=p.split(" "),d.zOrigin=(p.length>2&&(0===u||"0px"!==p[2])?parseFloat(p[2]):u)||0,n.xs0=n.e=p[0]+" "+(p[1]||"50%")+" 0px",n=new ce(d,"zOrigin",0,0,n,-1,n.n),n.b=u,n.xs0=n.e=d.zOrigin):n.xs0=n.e=p):se(p+"",d)),c&&(s._transformType=d.svg&&Te||!f&&3!==this._transformType?2:3),n},prefix:!0}),ve("boxShadow",{defaultValue:"0px 0px 0px 0px #999",prefix:!0,color:!0,multi:!0,keyword:"inset"}),ve("borderRadius",{defaultValue:"0px",parser:function(t,e,i,n,a){e=this.format(e);var o,h,l,_,u,p,f,c,m,d,g,v,y,T,w,x,b=["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],P=t.style;for(m=parseFloat(t.offsetWidth),d=parseFloat(t.offsetHeight),o=e.split(" "),h=0;b.length>h;h++)this.p.indexOf("border")&&(b[h]=W(b[h])),u=_=Q(t,b[h],r,!1,"0px"),-1!==u.indexOf(" ")&&(_=u.split(" "),u=_[0],_=_[1]),p=l=o[h],f=parseFloat(u),v=u.substr((f+"").length),y="="===p.charAt(1),y?(c=parseInt(p.charAt(0)+"1",10),p=
vendor: 9,852 bytes, lines 1726-1727
1726p.substr(2),c*=parseFloat(p),g=p.substr((c+"").length-(0>c?1:0))||""):(c=parseFloat(p),g=p.substr((c+"").length)),""===g&&(g=s[i]||v),g!==v&&(T=$(t,"borderLeft",f,v),w=$(t,"borderTop",f,v),"%"===g?(u=100*(T/m)+"%",_=100*(w/d)+"%"):"em"===g?(x=$(t,"borderLeft",1,"em"),u=T/x+"em",_=w/x+"em"):(u=T+"px",_=w+"px"),y&&(p=parseFloat(u)+c+g,l=parseFloat(_)+c+g)),a=me(P,b[h],u+" "+_,p+" "+l,!1,"0px",a);return a},prefix:!0,formatter:ue("0px 0px 0px 0px",!1,!0)}),ve("backgroundPosition",{defaultValue:"0 0",parser:function(t,e,i,s,n,a){var o,h,l,_,u,p,f="background-position",c=r||Z(t,null),d=this.format((c?m?c.getPropertyValue(f+"-x")+" "+c.getPropertyValue(f+"-y"):c.getPropertyValue(f):t.currentStyle.backgroundPositionX+" "+t.currentStyle.backgroundPositionY)||"0 0"),g=this.format(e);if(-1!==d.indexOf("%")!=(-1!==g.indexOf("%"))&&(p=Q(t,"backgroundImage").replace(R,""),p&&"none"!==p)){for(o=d.split(" "),h=g.split(" "),X.setAttribute("src",p),l=2;--l>-1;)d=o[l],_=-1!==d.indexOf("%"),_!==(-1!==h[l].indexOf("%"))&&(u=0===l?t.offsetWidth-X.width:t.offsetHeight-X.height,o[l]=_?parseFloat(d)/100*u+"px":100*(parseFloat(d)/u)+"%");d=o.join(" ")}return this.parseComplex(t.style,d,g,n,a)},formatter:se}),ve("backgroundSize",{defaultValue:"0 0",formatter:se}),ve("perspective",{defaultValue:"0px",prefix:!0}),ve("perspectiveOrigin",{defaultValue:"50% 50%",prefix:!0}),ve("transformStyle",{prefix:!0}),ve("backfaceVisibility",{prefix:!0}),ve("userSelect",{prefix:!0}),ve("margin",{parser:pe("marginTop,marginRight,marginBottom,marginLeft")}),ve("padding",{parser:pe("paddingTop,paddingRight,paddingBottom,paddingLeft")}),ve("clip",{defaultValue:"rect(0px,0px,0px,0px)",parser:function(t,e,i,s,n,a){var o,h,l;return 9>m?(h=t.currentStyle,l=8>m?" ":",",o="rect("+h.clipTop+l+h.clipRight+l+h.clipBottom+l+h.clipLeft+")",e=this.format(e).split(",").join(l)):(o=this.format(Q(t,this.p,r,!1,this.dflt)),e=this.format(e)),this.parseComplex(t.style,o,e,n,a)}}),ve("textShadow",{defaultValue:"0px 0px 0px #999",color:!0,multi:!0}),ve("autoRound,strictUnits",{parser:function(t,e,i,s,r){return r}}),ve("border",{defaultValue:"0px solid #000",parser:function(t,e,i,s,n,a){return this.parseComplex(t.style,this.format(Q(t,"borderTopWidth",r,!1,"0px")+" "+Q(t,"borderTopStyle",r,!1,"solid")+" "+Q(t,"borderTopColor",r,!1,"#000")),this.format(e),n,a)},color:!0,formatter:function(t){var e=t.split(" ");return e[0]+" "+(e[1]||"solid")+" "+(t.match(_e)||["#000"])[0]}}),ve("borderWidth",{parser:pe("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}),ve("float,cssFloat,styleFloat",{parser:function(t,e,i,s,r){var n=t.style,a="cssFloat"in n?"cssFloat":"styleFloat";return new ce(n,a,0,0,r,-1,i,!1,0,n[a],e)}});var Ee=function(t){var e,i=this.t,s=i.filter||Q(this.data,"filter")||"",r=0|this.s+this.c*t;100===r&&(-1===s.indexOf("atrix(")&&-1===s.indexOf("radient(")&&-1===s.indexOf("oader(")?(i.removeAttribute("filter"),e=!Q(this.data,"filter")):(i.filter=s.replace(b,""),e=!0)),e||(this.xn1&&(i.filter=s=s||"alpha(opacity="+r+")"),-1===s.indexOf("pacity")?0===r&&this.xn1||(i.filter=s+" alpha(opacity="+r+")"):i.filter=s.replace(w,"opacity="+r))};ve("opacity,alpha,autoAlpha",{defaultValue:"1",parser:function(t,e,i,s,n,a){var o=parseFloat(Q(t,"opacity",r,!1,"1")),h=t.style,l="autoAlpha"===i;return"string"==typeof e&&"="===e.charAt(1)&&(e=("-"===e.charAt(0)?-1:1)*parseFloat(e.substr(2))+o),l&&1===o&&"hidden"===Q(t,"visibility",r)&&0!==e&&(o=0),j?n=new ce(h,"opacity",o,e-o,n):(n=new ce(h,"opacity",100*o,100*(e-o),n),n.xn1=l?1:0,h.zoom=1,n.type=2,n.b="alpha(opacity="+n.s+")",n.e="alpha(opacity="+(n.s+n.c)+")",n.data=t,n.plugin=a,n.setRatio=Ee),l&&(n=new ce(h,"visibility",0,0,n,-1,null,!1,0,0!==o?"inherit":"hidden",0===e?"hidden":"inherit"),n.xs0="inherit",s._overwriteProps.push(n.n),s._overwriteProps.push(i)),n}});var Ne=function(t,e){e&&(t.removeProperty?(("ms"===e.substr(0,2)||"webkit"===e.substr(0,6))&&(e="-"+e),t.removeProperty(e.replace(S,"-$1").toLowerCase())):t.removeAttribute(e))
1727},Le=function(t){if(this.t._gsClassPT=this,1===t||0===t){this.t.setAttribute("class",0===t?this.b:this.e);for(var e=this.data,i=this.t.style;e;)e.v?i[e.p]=e.v:Ne(i,e.p),e=e._next;1===t&&this.t._gsClassPT===this&&(this.t._gsClassPT=null)}else this.t.getAttribute("class")!==this.e&&this.t.setAttribute("class",this.e)};ve("className",{parser:function(t,e,s,n,a,o,h){var l,_,u,p,f,c=t.getAttribute("class")||"",m=t.style.cssText;if(a=n._classNamePT=new ce(t,s,0,0,a,2),a.setRatio=Le,a.pr=-11,i=!0,a.b=c,_=K(t,r),u=t._gsClassPT){for(p={},f=u.data;f;)p[f.p]=1,f=f._next;u.setRatio(1)}return t._gsClassPT=a,a.e="="!==e.charAt(1)?e:c.replace(RegExp("\\s*\\b"+e.substr(2)+"\\b"),"")+("+"===e.charAt(0)?" "+e.substr(2):""),n._tween._duration&&(t.setAttribute("class",a.e),l=J(t,_,K(t),h,p),t.setAttribute("class",c),a.data=l.firstMPT,t.style.cssText=m,a=a.xfirst=n.parse(t,l.difs,a,o)),a}});var Xe=function(t){if((1===t||0===t)&&this.data._totalTime===this.data._totalDuration&&"isFromStart"!==this.data.data){var e,i,s,r,n=this.t.style,a=h.transform.parse;if("all"===this.e)n.cssText="",r=!0;else for(e=this.e.split(" ").join("").split(","),s=e.length;--s>-1;)i=e[s],h[i]&&(h[i].parse===a?r=!0:i="transformOrigin"===i?Pe:h[i].p),Ne(n,i);r&&(Ne(n,xe),this.t._gsTransform&&delete this.t._gsTransform)}};for(ve("clearProps",{parser:function(t,e,s,r,n){return n=new ce(t,s,0,0,n,2),n.setRatio=Xe,n.e=e,n.pr=-10,n.data=r._tween,i=!0,n}}),l="bezier,throwProps,physicsProps,physics2D".split(","),de=l.length;de--;)ye(l[de]);l=a.prototype,l._firstPT=l._lastParsedTransform=l._transform=null,l._onInitTween=function(t,e,o){if(!t.nodeType)return!1;this._target=t,this._tween=o,this._vars=e,_=e.autoRound,i=!1,s=e.suffixMap||a.suffixMap,r=Z(t,""),n=this._overwriteProps;var h,l,f,m,d,g,v,y,T,w=t.style;if(u&&""===w.zIndex&&(h=Q(t,"zIndex",r),("auto"===h||""===h)&&this._addLazySet(w,"zIndex",0)),"string"==typeof e&&(m=w.cssText,h=K(t,r),w.cssText=m+";"+e,h=J(t,h,K(t)).difs,!j&&x.test(e)&&(h.opacity=parseFloat(RegExp.$1)),e=h,w.cssText=m),this._firstPT=l=this.parse(t,e,null),this._transformType){for(T=3===this._transformType,xe?p&&(u=!0,""===w.zIndex&&(v=Q(t,"zIndex",r),("auto"===v||""===v)&&this._addLazySet(w,"zIndex",0)),c&&this._addLazySet(w,"WebkitBackfaceVisibility",this._vars.WebkitBackfaceVisibility||(T?"visible":"hidden"))):w.zoom=1,f=l;f&&f._next;)f=f._next;y=new ce(t,"transform",0,0,null,2),this._linkCSSP(y,null,f),y.setRatio=T&&Se?Ie:xe?Fe:ze,y.data=this._transform||Me(t,r,!0),y.tween=o,n.pop()}if(i){for(;l;){for(g=l._next,f=m;f&&f.pr>l.pr;)f=f._next;(l._prev=f?f._prev:d)?l._prev._next=l:m=l,(l._next=f)?f._prev=l:d=l,l=g}this._firstPT=m}return!0},l.parse=function(t,e,i,n){var a,o,l,u,p,f,c,m,d,g,v=t.style;for(a in e)f=e[a],o=h[a],o?i=o.parse(t,f,a,this,i,n,e):(p=Q(t,a,r)+"",d="string"==typeof f,"color"===a||"fill"===a||"stroke"===a||-1!==a.indexOf("Color")||d&&P.test(f)?(d||(f=le(f),f=(f.length>3?"rgba(":"rgb(")+f.join(",")+")"),i=me(v,a,p,f,!0,"transparent",i,0,n)):!d||-1===f.indexOf(" ")&&-1===f.indexOf(",")?(l=parseFloat(p),c=l||0===l?p.substr((l+"").length):"",(""===p||"auto"===p)&&("width"===a||"height"===a?(l=ie(t,a,r),c="px"):"left"===a||"top"===a?(l=H(t,a,r),c="px"):(l="opacity"!==a?0:1,c="")),g=d&&"="===f.charAt(1),g?(u=parseInt(f.charAt(0)+"1",10),f=f.substr(2),u*=parseFloat(f),m=f.replace(T,"")):(u=parseFloat(f),m=d?f.replace(T,""):""),""===m&&(m=a in s?s[a]:c),f=u||0===u?(g?u+l:u)+m:e[a],c!==m&&""!==m&&(u||0===u)&&l&&(l=$(t,a,l,c),"%"===m?(l/=$(t,a,100,"%")/100,e.strictUnits!==!0&&(p=l+"%")):"em"===m?l/=$(t,a,1,"em"):"px"!==m&&(u=$(t,a,u,m),m="px"),g&&(u||0===u)&&(f=u+l+m)),g&&(u+=l),!l&&0!==l||!u&&0!==u?void 0!==v[a]&&(f||"NaN"!=f+""&&null!=f)?(i=new ce(v,a,u||l||0,0,i,-1,a,!1,0,p,f),i.xs0="none"!==f||"display"!==a&&-1===a.indexOf("Style")?f:p):q("invalid "+a+" tween value: "+e[a]):(i=new ce(v,a,l,u-l,i,0,a,_!==!1&&("px"===m||"zIndex"===a),0,p,f),i.xs0=m)):i=me(v,a,p,f,!0,null,i,0,n)),n&&i&&!i.plugin&&(i.plugin=n);return i},l.setRatio=function(t){var e,i,s,r=this._firstPT,n=1e-6;if(1!==t||this._tween._time!==this._tween._duration&&0!==this._tween._time)if(t||this._tween._time!==this._tween._duration&&0!==this._tween._time||this._tween._rawPrevTime===-1e-6)for(;r;){if(e=r.c*t+r.s,r.r?e=Math.round(e):n>e&&e>-n&&(e=0),r.type)if(1===r.type)if(s=r.l,2===s)r.t[r.p]=r.xs0+e+r.xs1+r.xn1+r.xs2;else if(3===s)r.t[r.p]=r.xs0+e+r.xs1+r.xn1+r.xs2+r.xn2+r.xs3;else if(4===s)r.t[r.p]=r.xs0+e+r.xs1+r.xn1+r.xs2+r.xn2+r.xs3+r.xn3+r.xs4;else if(5===s)r.t[r.p]=r.xs0+e+r.xs1+r.xn1+r.xs2+r.xn2+r.xs3+r.xn3+r.xs4+r.xn4+r.xs5;else{for(i=r.xs0+e+r.xs1,s=1;r.l>s;s++)i+=r["xn"+s]+r["xs"+(s+1)];r.t[r.p]=i}else-1===r.type?r.t[r.p]=r.xs0:r.setRatio&&r.setRatio(t);else r.t[r.p]=e+r.xs0;r=r._next}else for(;r;)2!==r.type?r.t[r.p]=r.b:r.setRatio(t),r=r._next;else for(;r;)2!==r.type?r.t[r.p]=r.e:r.setRatio(t),r=r._next},l._enableTransforms=function(t){this._transform=this._transform||Me(this._target,r,!0),this._transformType=this._transform.svg&&Te||!t&&3!==this._transformType?2:3};var Ue=function(){this.t[this.p]=this.e,this.data._linkCSSP(this,this._next,null,!0)};l._addLazySet=function(t,e,i){var s=this._firstPT=new ce(t,e,0,0,this._firstPT,2);s.e=i,s.setRatio=Ue,s.data=this},l._linkCSSP=function(t,e,i,s){return t&&(e&&(e._prev=t),t._next&&(t._next._prev=t._prev),t._prev?t._prev._next=t._next:this._firstPT===t&&(this._firstPT=t._next,s=!0),i?i._next=t:s||null!==this._firstPT||(this._firstPT=t),t._next=e,t._prev=i),t},l._kill=function(e){var i,s,r,n=e;if(e.autoAlpha||e.alpha){n={};for(s in e)n[s]=e[s];n.opacity=1,n.autoAlpha&&(n.visibility=1)}return e.className&&(i=this._classNamePT)&&(r=i.xfirst,r&&r._prev?this._linkCSSP(r._prev,i._next,r._prev._prev):r===this._firstPT&&(this._firstPT=i._next),i._next&&this._linkCSSP(i._next,i._next._next,r._prev),this._classNamePT=null),t.prototype._kill.call(this,n)};
1727var Ye=function(t,e,i){var s,r,n,a;if(t.slice)for(r=t.length;--r>-1;)Ye(t[r],e,i);else for(s=t.childNodes,r=s.length;--r>-1;)n=s[r],a=n.type,n.style&&(e.push(K(n)),i&&i.push(n)),1!==a&&9!==a&&11!==a||!n.childNodes.length||Ye(n,e,i)};return a.cascadeTo=function(t,i,s){var r,n,a,o,h=e.to(t,i,s),l=[h],_=[],u=[],p=[],f=e._internals.reservedProps;for(t=h._targets||h.target,Ye(t,_,p),h.render(i,!0,!0),Ye(t,u),h.render(0,!0,!0),h._enabled(!0),r=p.length;--r>-1;)if(n=J(p[r],_[r],u[r]),n.firstMPT){n=n.difs;for(a in s)f[a]&&(n[a]=s[a]);o={};for(a in n)o[a]=_[r][a];l.push(e.fromTo(p[r],i,o,n))}return l},t.activate([a]),a},!0),function(){var t=_gsScope._gsDefine.plugin({propName:"roundProps",priority:-1,API:2,init:function(t,e,i){return this._tween=i,!0}}),e=t.prototype;e._onInitAllProps=function(){for(var t,e,i,s=this._tween,r=s.vars.roundProps instanceof Array?s.vars.roundProps:s.vars.roundProps.split(","),n=r.length,a={},o=s._propLookup.roundProps;--n>-1;)a[r[n]]=1;for(n=r.length;--n>-1;)for(t=r[n],e=s._firstPT;e;)i=e._next,e.pg?e.t._roundProps(a,!0):e.n===t&&(this._add(e.t,t,e.s,e.c),i&&(i._prev=e._prev),e._prev?e._prev._next=i:s._firstPT===e&&(s._firstPT=i),e._next=e._prev=null,s._propLookup[t]=o),e=i;return!1},e._add=function(t,e,i,s){this._addTween(t,e,i,i+s,e,!0),this._overwriteProps.push(e)}}(),_gsScope._gsDefine.plugin({propName:"attr",API:2,version:"0.3.3",init:function(t,e){var i,s,r;if("function"!=typeof t.setAttribute)return!1;this._target=t,this._proxy={},this._start={},this._end={};for(i in e)this._start[i]=this._proxy[i]=s=t.getAttribute(i),r=this._addTween(this._proxy,i,parseFloat(s),e[i],i),this._end[i]=r?r.s+r.c:e[i],this._overwriteProps.push(i);return!0},set:function(t){this._super.setRatio.call(this,t);for(var e,i=this._overwriteProps,s=i.length,r=1===t?this._end:t?this._proxy:this._start;--s>-1;)e=i[s],this._target.setAttribute(e,r[e]+"")}}),_gsScope._gsDefine.plugin({propName:"directionalRotation",version:"0.2.1",API:2,init:function(t,e){"object"!=typeof e&&(e={rotation:e}),this.finals={};var i,s,r,n,a,o,h=e.useRadians===!0?2*Math.PI:360,l=1e-6;for(i in e)"useRadians"!==i&&(o=(e[i]+"").split("_"),s=o[0],r=parseFloat("function"!=typeof t[i]?t[i]:t[i.indexOf("set")||"function"!=typeof t["get"+i.substr(3)]?i:"get"+i.substr(3)]()),n=this.finals[i]="string"==typeof s&&"="===s.charAt(1)?r+parseInt(s.charAt(0)+"1",10)*Number(s.substr(2)):Number(s)||0,a=n-r,o.length&&(s=o.join("_"),-1!==s.indexOf("short")&&(a%=h,a!==a%(h/2)&&(a=0>a?a+h:a-h)),-1!==s.indexOf("_cw")&&0>a?a=(a+9999999999*h)%h-(0|a/h)*h:-1!==s.indexOf("ccw")&&a>0&&(a=(a-9999999999*h)%h-(0|a/h)*h)),(a>l||-l>a)&&(this._addTween(t,i,r,r+a,i),this._overwriteProps.push(i)));return!0},set:function(t){var e;if(1!==t)this._super.setRatio.call(this,t);else for(e=this._firstPT;e;)e.f?e.t[e.p](this.finals[e.p]):e.t[e.p]=this.finals[e.p],e=e._next}})._autoCSS=!0,_gsScope._gsDefine("easing.Back",["easing.Ease"],function(t){var e,i,s,r=_gsScope.GreenSockGlobals||_gsScope,n=r.com.greensock,a=2*Math.PI,o=Math.PI/2,h=n._class,l=function(e,i){var s=h("easing."+e,function(){},!0),r=s.prototype=new t;return r.constructor=s,r.getRatio=i,s},_=t.register||function(){},u=function(t,e,i,s){var r=h("easing."+t,{easeOut:new e,easeIn:new i,easeInOut:new s},!0);return _(r,t),r},p=function(t,e,i){this.t=t,this.v=e,i&&(this.next=i,i.prev=this,this.c=i.v-e,this.gap=i.t-t)},f=function(e,i){var s=h("easing."+e,function(t){this._p1=t||0===t?t:1.70158,this._p2=1.525*this._p1},!0),r=s.prototype=new t;return r.constructor=s,r.getRatio=i,r.config=function(t){return new s(t)},s},c=u("Back",f("BackOut",function(t){return(t-=1)*t*((this._p1+1)*t+this._p1)+1}),f("BackIn",function(t){return t*t*((this._p1+1)*t-this._p1)}),f("BackInOut",function(t){return 1>(t*=2)?.5*t*t*((this._p2+1)*t-this._p2):.5*((t-=2)*t*((this._p2+1)*t+this._p2)+2)})),m=h("easing.SlowMo",function(t,e,i){e=e||0===e?e:.7,null==t?t=.7:t>1&&(t=1),this._p=1!==t?e:0,this._p1=(1-t)/2,this._p2=t,this._p3=this._p1+this._p2,this._calcEnd=i===!0},!0),d=m.prototype=new t;return d.constructor=m,d.getRatio=function(t){var e=t+(.5-t)*this._p;return this._p1>t?this._calcEnd?1-(t=1-t/this._p1)*t:e-(t=1-t/this._p1)*t*t*t*e:t>this._p3?this._calcEnd?1-(t=(t-this._p3)/this._p1)*t:e+(t-e)*(t=(t-this._p3)/this._p1)*t*t*t:this._calcEnd?1:e}
vendor: 9,306 bytes, line 1727
1727,m.ease=new m(.7,.7),d.config=m.config=function(t,e,i){return new m(t,e,i)},e=h("easing.SteppedEase",function(t){t=t||1,this._p1=1/t,this._p2=t+1},!0),d=e.prototype=new t,d.constructor=e,d.getRatio=function(t){return 0>t?t=0:t>=1&&(t=.999999999),(this._p2*t>>0)*this._p1},d.config=e.config=function(t){return new e(t)},i=h("easing.RoughEase",function(e){e=e||{};for(var i,s,r,n,a,o,h=e.taper||"none",l=[],_=0,u=0|(e.points||20),f=u,c=e.randomize!==!1,m=e.clamp===!0,d=e.template instanceof t?e.template:null,g="number"==typeof e.strength?.4*e.strength:.4;--f>-1;)i=c?Math.random():1/u*f,s=d?d.getRatio(i):i,"none"===h?r=g:"out"===h?(n=1-i,r=n*n*g):"in"===h?r=i*i*g:.5>i?(n=2*i,r=.5*n*n*g):(n=2*(1-i),r=.5*n*n*g),c?s+=Math.random()*r-.5*r:f%2?s+=.5*r:s-=.5*r,m&&(s>1?s=1:0>s&&(s=0)),l[_++]={x:i,y:s};for(l.sort(function(t,e){return t.x-e.x}),o=new p(1,1,null),f=u;--f>-1;)a=l[f],o=new p(a.x,a.y,o);this._prev=new p(0,0,0!==o.t?o:o.next)},!0),d=i.prototype=new t,d.constructor=i,d.getRatio=function(t){var e=this._prev;if(t>e.t){for(;e.next&&t>=e.t;)e=e.next;e=e.prev}else for(;e.prev&&e.t>=t;)e=e.prev;return this._prev=e,e.v+(t-e.t)/e.gap*e.c},d.config=function(t){return new i(t)},i.ease=new i,u("Bounce",l("BounceOut",function(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}),l("BounceIn",function(t){return 1/2.75>(t=1-t)?1-7.5625*t*t:2/2.75>t?1-(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)}),l("BounceInOut",function(t){var e=.5>t;return t=e?1-2*t:2*t-1,t=1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,e?.5*(1-t):.5*t+.5})),u("Circ",l("CircOut",function(t){return Math.sqrt(1-(t-=1)*t)}),l("CircIn",function(t){return-(Math.sqrt(1-t*t)-1)}),l("CircInOut",function(t){return 1>(t*=2)?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)})),s=function(e,i,s){var r=h("easing."+e,function(t,e){this._p1=t>=1?t:1,this._p2=(e||s)/(1>t?t:1),this._p3=this._p2/a*(Math.asin(1/this._p1)||0),this._p2=a/this._p2},!0),n=r.prototype=new t;return n.constructor=r,n.getRatio=i,n.config=function(t,e){return new r(t,e)},r},u("Elastic",s("ElasticOut",function(t){return this._p1*Math.pow(2,-10*t)*Math.sin((t-this._p3)*this._p2)+1},.3),s("ElasticIn",function(t){return-(this._p1*Math.pow(2,10*(t-=1))*Math.sin((t-this._p3)*this._p2))},.3),s("ElasticInOut",function(t){return 1>(t*=2)?-.5*this._p1*Math.pow(2,10*(t-=1))*Math.sin((t-this._p3)*this._p2):.5*this._p1*Math.pow(2,-10*(t-=1))*Math.sin((t-this._p3)*this._p2)+1},.45)),u("Expo",l("ExpoOut",function(t){return 1-Math.pow(2,-10*t)}),l("ExpoIn",function(t){return Math.pow(2,10*(t-1))-.001}),l("ExpoInOut",function(t){return 1>(t*=2)?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*(t-1)))})),u("Sine",l("SineOut",function(t){return Math.sin(t*o)}),l("SineIn",function(t){return-Math.cos(t*o)+1}),l("SineInOut",function(t){return-.5*(Math.cos(Math.PI*t)-1)})),h("easing.EaseLookup",{find:function(e){return t.map[e]}},!0),_(r.SlowMo,"SlowMo","ease,"),_(i,"RoughEase","ease,"),_(e,"SteppedEase","ease,"),c},!0)}),_gsScope._gsDefine&&_gsScope._gsQueue.pop()(),function(t,e){"use strict";var i=t.GreenSockGlobals=t.GreenSockGlobals||t;if(!i.TweenLite){var s,r,n,a,o,h=function(t){var e,s=t.split("."),r=i;for(e=0;s.length>e;e++)r[s[e]]=r=r[s[e]]||{};return r},l=h("com.greensock"),_=1e-10,u=function(t){var e,i=[],s=t.length;for(e=0;e!==s;i.push(t[e++]));return i},p=function(){},f=function(){var t=Object.prototype.toString,e=t.call([]);return function(i){return null!=i&&(i instanceof Array||"object"==typeof i&&!!i.push&&t.call(i)===e)}}(),c={},m=function(s,r,n,a){this.sc=c[s]?c[s].sc:[],c[s]=this,this.gsClass=null,this.func=n;var o=[];this.check=function(l){for(var _,u,p,f,d=r.length,g=d;--d>-1;)(_=c[r[d]]||new m(r[d],[])).gsClass?(o[d]=_.gsClass,g--):l&&_.sc.push(this);if(0===g&&n)for(u=("com.greensock."+s).split("."),p=u.pop(),f=h(u.join("."))[p]=this.gsClass=n.apply(n,o),a&&(i[p]=f,"function"==typeof define&&define.amd?define((t.GreenSockAMDPath?t.GreenSockAMDPath+"/":"")+s.split(".").pop(),[],function(){return f}):s===e&&"undefined"!=typeof module&&module.exports&&(module.exports=f)),d=0;this.sc.length>d;d++)this.sc[d].check()},this.check(!0)},d=t._gsDefine=function(t,e,i,s){return new m(t,e,i,s)},g=l._class=function(t,e,i){return e=e||function(){},d(t,[],function(){return e},i),e};d.globals=i;var v=[0,0,1,1],y=[],T=g("easing.Ease",function(t,e,i,s){this._func=t,this._type=i||0,this._power=s||0,this._params=e?v.concat(e):v},!0),w=T.map={},x=T.register=function(t,e,i,s){for(var r,n,a,o,h=e.split(","),_=h.length,u=(i||"easeIn,easeOut,easeInOut").split(",");--_>-1;)for(n=h[_],r=s?g("easing."+n,null,!0):l.easing[n]||{},a=u.length;--a>-1;)o=u[a],w[n+"."+o]=w[o+n]=r[o]=t.getRatio?t:t[o]||new t};for(n=T.prototype,n._calcEnd=!1,n.getRatio=function(t){if(this._func)return this._params[0]=t,this._func.apply(null,this._params);var e=this._type,i=this._power,s=1===e?1-t:2===e?t:.5>t?2*t:2*(1-t);return 1===i?s*=s:2===i?s*=s*s:3===i?s*=s*s*s:4===i&&(s*=s*s*s*s),1===e?1-s:2===e?s:.5>t?s/2:1-s/2},s=["Linear","Quad","Cubic","Quart","Quint,Strong"],r=s.length;--r>-1;)n=s[r]+",Power"+r,x(new T(null,null,1,r),n,"easeOut",!0),x(new T(null,null,2,r),n,"easeIn"+(0===r?",easeNone":"")),x(new T(null,null,3,r),n,"easeInOut");w.linear=l.easing.Linear.easeIn,w.swing=l.easing.Quad.easeInOut;var b=g("events.EventDispatcher",function(t){this._listeners={},this._eventTarget=t||this});n=b.prototype,n.addEventListener=function(t,e,i,s,r){r=r||0;var n,h,l=this._listeners[t],_=0;for(null==l&&(this._listeners[t]=l=[]),h=l.length;--h>-1;)n=l[h],n.c===e&&n.s===i?l.splice(h,1):0===_&&r>n.pr&&(_=h+1);l.splice(_,0,{c:e,s:i,up:s,pr:r}),this!==a||o||a.wake()},n.removeEventListener=function(t,e){var i,s=this._listeners[t];if(s)for(i=s.length;--i>-1;)if(s[i].c===e)return s.splice(i,1),void 0},n.dispatchEvent=function(t){var e,i,s,r=this._listeners[t];if(r)for(e=r.length,i=this._eventTarget;--e>-1;)s=r[e],s&&(s.up?s.c.call(s.s||i,{type:t,target:i}):s.c.call(s.s||i))};var P=t.requestAnimationFrame,S=t.cancelAnimationFrame,k=Date.now||function(){return(new Date).getTime()},R=k();for(s=["ms","moz","webkit","o"],r=s.length;--r>-1&&!P;)P=t[s[r]+"RequestAnimationFrame"],S=t[s[r]+"CancelAnimationFrame"]||t[s[r]+"CancelRequestAnimationFrame"];g("Ticker",function(t,e){var i,s,r,n,h,l=this,u=k(),f=e!==!1&&P,c=500,m=33,d="tick",g=function(t){var e,a,o=k()-R;o>c&&(u+=o-m),R+=o,l.time=(R-u)/1e3,e=l.time-h,(!i||e>0||t===!0)&&(l.frame++,h+=e+(e>=n?.004:n-e),a=!0),t!==!0&&(r=s(g)),a&&l.dispatchEvent(d)};b.call(l),l.time=l.frame=0,l.tick=function(){g(!0)},l.lagSmoothing=function(t,e){c=t||1/_,m=Math.min(e,c,0)},l.sleep=function(){null!=r&&(f&&S?S(r):clearTimeout(r),s=p,r=null,l===a&&(o=!1))},l.wake=function(){null!==r?l.sleep():l.frame>10&&(R=k()-c+5),s=0===i?p:f&&P?P:function(t){return setTimeout(t,0|1e3*(h-l.time)+1)},l===a&&(o=!0),g(2)},l.fps=function(t){return arguments.length?(i=t,n=1/(i||60),h=this.time+n,l.wake(),void 0):i},l.useRAF=function(t){return arguments.length?(l.sleep(),f=t,l.fps(i),void 0):f},l.fps(t),setTimeout(function(){f&&(!r||5>l.frame)&&l.useRAF(!1)},1500)}),n=l.Ticker.prototype=new l.events.EventDispatcher,n.constructor=l.Ticker;var A=g("core.Animation",function(t,e){if(this.vars=e=e||{},this._duration=this._totalDuration=t||0,this._delay=Number(e.delay)||0,this._timeScale=1,this._active=e.immediateRender===!0,this.data=e.data,this._reversed=e.reversed===!0,B){o||a.wake();var i=this.vars.useFrames?j:B;i.add(this,i._time),this.vars.paused&&this.paused(!0)}});a=A.ticker=new l.Ticker,n=A.prototype,n._dirty=n._gc=n._initted=n._paused=!1,n._totalTime=n._time=0,n._rawPrevTime=-1,n._next=n._last=n._onUpdate=n._timeline=n.timeline=null,n._paused=!1;var O=function(){o&&k()-R>2e3&&a.wake(),setTimeout(O,2e3)};O(),n.play=function(t,e){return null!=t&&this.seek(t,e),this.reversed(!1).paused(!1)},n.pause=function(t,e){return null!=t&&this.seek(t,e),this.paused(!0)},n.resume=function(t,e){return null!=t&&this.seek(t,e),this.paused(!1)},n.seek=function(t,e){return this.totalTime(Number(t),e!==!1)},n.restart=function(t,e){return this.reversed(!1).paused(!1).totalTime(t?-this._delay:0,e!==!1,!0)},n.reverse=function(t,e){return null!=t&&this.seek(t||this.totalDuration(),e),this.reversed(!0).paused(!1)},n.render=function(){},n.invalidate=function(){return this._time=this._totalTime=0,this._initted=this._gc=!1,this._rawPrevTime=-1,(this._gc||!this.timeline)&&this._enabled(!0),this},n.isActive=function(){var t,e=this._timeline,i=this._startTime;return!e||!this._gc&&!this._paused&&e.isActive()&&(t=e.rawTime())>=i&&i+this.totalDuration()/this._timeScale>t},n._enabled=function(t,e){return o||a.wake(),this._gc=!t,this._active=this.isActive(),e!==!0&&(t&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!t&&this.timeline&&this._timeline._remove(this,!0)),!1},n._kill=function(){return this._enabled(!1,!1)},n.kill=function(t,e){return this._kill(t,e),this},n._uncache=function(t){for(var e=t?this:this.timeline;e;)e._dirty=!0,e=e.timeline;return this},n._swapSelfInParams=function(t){for(var e=t.length,i=t.concat();--e>-1;)"{self}"===t[e]&&(i[e]=this);return i}
vendor: 4,111 bytes, line 1727
1727,n.eventCallback=function(t,e,i,s){if("on"===(t||"").substr(0,2)){var r=this.vars;if(1===arguments.length)return r[t];null==e?delete r[t]:(r[t]=e,r[t+"Params"]=f(i)&&-1!==i.join("").indexOf("{self}")?this._swapSelfInParams(i):i,r[t+"Scope"]=s),"onUpdate"===t&&(this._onUpdate=e)}return this},n.delay=function(t){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+t-this._delay),this._delay=t,this):this._delay},n.duration=function(t){return arguments.length?(this._duration=this._totalDuration=t,this._uncache(!0),this._timeline.smoothChildTiming&&this._time>0&&this._time<this._duration&&0!==t&&this.totalTime(this._totalTime*(t/this._duration),!0),this):(this._dirty=!1,this._duration)},n.totalDuration=function(t){return this._dirty=!1,arguments.length?this.duration(t):this._totalDuration},n.time=function(t,e){return arguments.length?(this._dirty&&this.totalDuration(),this.totalTime(t>this._duration?this._duration:t,e)):this._time},n.totalTime=function(t,e,i){if(o||a.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(0>t&&!i&&(t+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var s=this._totalDuration,r=this._timeline;if(t>s&&!i&&(t=s),this._startTime=(this._paused?this._pauseTime:r._time)-(this._reversed?s-t:t)/this._timeScale,r._dirty||this._uncache(!1),r._timeline)for(;r._timeline;)r._timeline._time!==(r._startTime+r._totalTime)/r._timeScale&&r.totalTime(r._totalTime,!0),r=r._timeline}this._gc&&this._enabled(!0,!1),(this._totalTime!==t||0===this._duration)&&(this.render(t,e,!1),I.length&&V())}return this},n.progress=n.totalProgress=function(t,e){return arguments.length?this.totalTime(this.duration()*t,e):this._time/this.duration()},n.startTime=function(t){return arguments.length?(t!==this._startTime&&(this._startTime=t,this.timeline&&this.timeline._sortChildren&&this.timeline.add(this,t-this._delay)),this):this._startTime},n.endTime=function(t){return this._startTime+(0!=t?this.totalDuration():this.duration())/this._timeScale},n.timeScale=function(t){if(!arguments.length)return this._timeScale;if(t=t||_,this._timeline&&this._timeline.smoothChildTiming){var e=this._pauseTime,i=e||0===e?e:this._timeline.totalTime();this._startTime=i-(i-this._startTime)*this._timeScale/t}return this._timeScale=t,this._uncache(!1)},n.reversed=function(t){return arguments.length?(t!=this._reversed&&(this._reversed=t,this.totalTime(this._timeline&&!this._timeline.smoothChildTiming?this.totalDuration()-this._totalTime:this._totalTime,!0)),this):this._reversed},n.paused=function(t){if(!arguments.length)return this._paused;var e,i,s=this._timeline;return t!=this._paused&&s&&(o||t||a.wake(),e=s.rawTime(),i=e-this._pauseTime,!t&&s.smoothChildTiming&&(this._startTime+=i,this._uncache(!1)),this._pauseTime=t?e:null,this._paused=t,this._active=this.isActive(),!t&&0!==i&&this._initted&&this.duration()&&this.render(s.smoothChildTiming?this._totalTime:(e-this._startTime)/this._timeScale,!0,!0)),this._gc&&!t&&this._enabled(!0,!1),this};var C=g("core.SimpleTimeline",function(t){A.call(this,0,t),this.autoRemoveChildren=this.smoothChildTiming=!0});n=C.prototype=new A,n.constructor=C,n.kill()._gc=!1,n._first=n._last=n._recent=null,n._sortChildren=!1,n.add=n.insert=function(t,e){var i,s;if(t._startTime=Number(e||0)+t._delay,t._paused&&this!==t._timeline&&(t._pauseTime=t._startTime+(this.rawTime()-t._startTime)/t._timeScale),t.timeline&&t.timeline._remove(t,!0),t.timeline=t._timeline=this,t._gc&&t._enabled(!0,!0),i=this._last,this._sortChildren)for(s=t._startTime;i&&i._startTime>s;)i=i._prev;return i?(t._next=i._next,i._next=t):(t._next=this._first,this._first=t),t._next?t._next._prev=t:this._last=t,t._prev=i,this._recent=t,this._timeline&&this._uncache(!0),this},n._remove=function(t,e){return t.timeline===this&&(e||t._enabled(!1,!0),t._prev?t._prev._next=t._next:this._first===t&&(this._first=t._next),t._next?t._next._prev=t._prev:this._last===t&&(this._last=t._prev),t._next=t._prev=t.timeline=null,t===this._recent&&(this._recent=this._last),this._timeline&&this._uncache(!0)),this}
vendor: 12,956 bytes, lines 1727-1728
1727,n.render=function(t,e,i){var s,r=this._first;for(this._totalTime=this._time=this._rawPrevTime=t;r;)s=r._next,(r._active||t>=r._startTime&&!r._paused)&&(r._reversed?r.render((r._dirty?r.totalDuration():r._totalDuration)-(t-r._startTime)*r._timeScale,e,i):r.render((t-r._startTime)*r._timeScale,e,i)),r=s},n.rawTime=function(){return o||a.wake(),this._totalTime};var D=g("TweenLite",function(e,i,s){if(A.call(this,i,s),this.render=D.prototype.render,null==e)throw"Cannot tween a null target.";this.target=e="string"!=typeof e?e:D.selector(e)||e;var r,n,a,o=e.jquery||e.length&&e!==t&&e[0]&&(e[0]===t||e[0].nodeType&&e[0].style&&!e.nodeType),h=this.vars.overwrite;if(this._overwrite=h=null==h?Y[D.defaultOverwrite]:"number"==typeof h?h>>0:Y[h],(o||e instanceof Array||e.push&&f(e))&&"number"!=typeof e[0])for(this._targets=a=u(e),this._propLookup=[],this._siblings=[],r=0;a.length>r;r++)n=a[r],n?"string"!=typeof n?n.length&&n!==t&&n[0]&&(n[0]===t||n[0].nodeType&&n[0].style&&!n.nodeType)?(a.splice(r--,1),this._targets=a=a.concat(u(n))):(this._siblings[r]=G(n,this,!1),1===h&&this._siblings[r].length>1&&Z(n,this,null,1,this._siblings[r])):(n=a[r--]=D.selector(n),"string"==typeof n&&a.splice(r+1,1)):a.splice(r--,1);else this._propLookup={},this._siblings=G(e,this,!1),1===h&&this._siblings.length>1&&Z(e,this,null,1,this._siblings);(this.vars.immediateRender||0===i&&0===this._delay&&this.vars.immediateRender!==!1)&&(this._time=-_,this.render(-this._delay))},!0),M=function(e){return e&&e.length&&e!==t&&e[0]&&(e[0]===t||e[0].nodeType&&e[0].style&&!e.nodeType)},z=function(t,e){var i,s={};for(i in t)U[i]||i in e&&"transform"!==i&&"x"!==i&&"y"!==i&&"width"!==i&&"height"!==i&&"className"!==i&&"border"!==i||!(!N[i]||N[i]&&N[i]._autoCSS)||(s[i]=t[i],delete t[i]);t.css=s};n=D.prototype=new A,n.constructor=D,n.kill()._gc=!1,n.ratio=0,n._firstPT=n._targets=n._overwrittenProps=n._startAt=null,n._notifyPluginsOfEnabled=n._lazy=!1,D.version="1.16.0",D.defaultEase=n._ease=new T(null,null,1,1),D.defaultOverwrite="auto",D.ticker=a,D.autoSleep=120,D.lagSmoothing=function(t,e){a.lagSmoothing(t,e)},D.selector=t.$||t.jQuery||function(e){var i=t.$||t.jQuery;return i?(D.selector=i,i(e)):"undefined"==typeof document?e:document.querySelectorAll?document.querySelectorAll(e):document.getElementById("#"===e.charAt(0)?e.substr(1):e)};var I=[],F={},E=D._internals={isArray:f,isSelector:M,lazyTweens:I},N=D._plugins={},L=E.tweenLookup={},X=0,U=E.reservedProps={ease:1,delay:1,overwrite:1,onComplete:1,onCompleteParams:1,onCompleteScope:1,useFrames:1,runBackwards:1,startAt:1,onUpdate:1,onUpdateParams:1,onUpdateScope:1,onStart:1,onStartParams:1,onStartScope:1,onReverseComplete:1,onReverseCompleteParams:1,onReverseCompleteScope:1,onRepeat:1,onRepeatParams:1,onRepeatScope:1,easeParams:1,yoyo:1,immediateRender:1,repeat:1,repeatDelay:1,data:1,paused:1,reversed:1,autoCSS:1,lazy:1,onOverwrite:1},Y={none:0,all:1,auto:2,concurrent:3,allOnStart:4,preexisting:5,"true":1,"false":0},j=A._rootFramesTimeline=new C,B=A._rootTimeline=new C,q=30,V=E.lazyRender=function(){var t,e=I.length;for(F={};--e>-1;)t=I[e],t&&t._lazy!==!1&&(t.render(t._lazy[0],t._lazy[1],!0),t._lazy=!1);I.length=0};B._startTime=a.time,j._startTime=a.frame,B._active=j._active=!0,setTimeout(V,1),A._updateRoot=D.render=function(){var t,e,i;if(I.length&&V(),B.render((a.time-B._startTime)*B._timeScale,!1,!1),j.render((a.frame-j._startTime)*j._timeScale,!1,!1),I.length&&V(),a.frame>=q){q=a.frame+(parseInt(D.autoSleep,10)||120);for(i in L){for(e=L[i].tweens,t=e.length;--t>-1;)e[t]._gc&&e.splice(t,1);0===e.length&&delete L[i]}if(i=B._first,(!i||i._paused)&&D.autoSleep&&!j._first&&1===a._listeners.tick.length){for(;i&&i._paused;)i=i._next;i||a.sleep()}}},a.addEventListener("tick",A._updateRoot);var G=function(t,e,i){var s,r,n=t._gsTweenID;if(L[n||(t._gsTweenID=n="t"+X++)]||(L[n]={target:t,tweens:[]}),e&&(s=L[n].tweens,s[r=s.length]=e,i))for(;--r>-1;)s[r]===e&&s.splice(r,1);return L[n].tweens},W=function(t,e,i,s){var r,n,a=t.vars.onOverwrite;return a&&(r=a(t,e,i,s)),a=D.onOverwrite,a&&(n=a(t,e,i,s)),r!==!1&&n!==!1},Z=function(t,e,i,s,r){var n,a,o,h;if(1===s||s>=4){for(h=r.length,n=0;h>n;n++)if((o=r[n])!==e)o._gc||W(o,e)&&o._enabled(!1,!1)&&(a=!0);else if(5===s)break;return a}var l,u=e._startTime+_,p=[],f=0,c=0===e._duration;for(n=r.length;--n>-1;)(o=r[n])===e||o._gc||o._paused||(o._timeline!==e._timeline?(l=l||Q(e,0,c),0===Q(o,l,c)&&(p[f++]=o)):u>=o._startTime&&o._startTime+o.totalDuration()/o._timeScale>u&&((c||!o._initted)&&2e-10>=u-o._startTime||(p[f++]=o)));for(n=f;--n>-1;)if(o=p[n],2===s&&o._kill(i,t,e)&&(a=!0),2!==s||!o._firstPT&&o._initted){if(2!==s&&!W(o,e))continue;o._enabled(!1,!1)&&(a=!0)}return a},Q=function(t,e,i){for(var s=t._timeline,r=s._timeScale,n=t._startTime;s._timeline;){if(n+=s._startTime,r*=s._timeScale,s._paused)return-100;s=s._timeline}return n/=r,n>e?n-e:i&&n===e||!t._initted&&2*_>n-e?_:(n+=t.totalDuration()/t._timeScale/r)>e+_?0:n-e-_};n._init=function(){var t,e,i,s,r,n=this.vars,a=this._overwrittenProps,o=this._duration,h=!!n.immediateRender,l=n.ease;if(n.startAt){this._startAt&&(this._startAt.render(-1,!0),this._startAt.kill()),r={};for(s in n.startAt)r[s]=n.startAt[s];if(r.overwrite=!1,r.immediateRender=!0,r.lazy=h&&n.lazy!==!1,r.startAt=r.delay=null,this._startAt=D.to(this.target,0,r),h)if(this._time>0)this._startAt=null;else if(0!==o)return}else if(n.runBackwards&&0!==o)if(this._startAt)this._startAt.render(-1,!0),this._startAt.kill(),this._startAt=null;else{0!==this._time&&(h=!1),i={};for(s in n)U[s]&&"autoCSS"!==s||(i[s]=n[s]);if(i.overwrite=0,i.data="isFromStart",i.lazy=h&&n.lazy!==!1,i.immediateRender=h,this._startAt=D.to(this.target,0,i),h){if(0===this._time)return}else this._startAt._init(),this._startAt._enabled(!1),this.vars.immediateRender&&(this._startAt=null)}if(this._ease=l=l?l instanceof T?l:"function"==typeof l?new T(l,n.easeParams):w[l]||D.defaultEase:D.defaultEase,n.easeParams instanceof Array&&l.config&&(this._ease=l.config.apply(l,n.easeParams)),this._easeType=this._ease._type,this._easePower=this._ease._power,this._firstPT=null,this._targets)for(t=this._targets.length;--t>-1;)this._initProps(this._targets[t],this._propLookup[t]={},this._siblings[t],a?a[t]:null)&&(e=!0);else e=this._initProps(this.target,this._propLookup,this._siblings,a);if(e&&D._onPluginEvent("_onInitAllProps",this),a&&(this._firstPT||"function"!=typeof this.target&&this._enabled(!1,!1)),n.runBackwards)for(i=this._firstPT;i;)i.s+=i.c,i.c=-i.c,i=i._next;this._onUpdate=n.onUpdate,this._initted=!0},n._initProps=function(e,i,s,r){var n,a,o,h,l,_;if(null==e)return!1;F[e._gsTweenID]&&V(),this.vars.css||e.style&&e!==t&&e.nodeType&&N.css&&this.vars.autoCSS!==!1&&z(this.vars,e);for(n in this.vars){if(_=this.vars[n],U[n])_&&(_ instanceof Array||_.push&&f(_))&&-1!==_.join("").indexOf("{self}")&&(this.vars[n]=_=this._swapSelfInParams(_,this));else if(N[n]&&(h=new N[n])._onInitTween(e,this.vars[n],this)){for(this._firstPT=l={_next:this._firstPT,t:h,p:"setRatio",s:0,c:1,f:!0,n:n,pg:!0,pr:h._priority},a=h._overwriteProps.length;--a>-1;)i[h._overwriteProps[a]]=this._firstPT;(h._priority||h._onInitAllProps)&&(o=!0),(h._onDisable||h._onEnable)&&(this._notifyPluginsOfEnabled=!0)}else this._firstPT=i[n]=l={_next:this._firstPT,t:e,p:n,f:"function"==typeof e[n],n:n,pg:!1,pr:0},l.s=l.f?e[n.indexOf("set")||"function"!=typeof e["get"+n.substr(3)]?n:"get"+n.substr(3)]():parseFloat(e[n]),l.c="string"==typeof _&&"="===_.charAt(1)?parseInt(_.charAt(0)+"1",10)*Number(_.substr(2)):Number(_)-l.s||0;l&&l._next&&(l._next._prev=l)}return r&&this._kill(r,e)?this._initProps(e,i,s,r):this._overwrite>1&&this._firstPT&&s.length>1&&Z(e,this,i,this._overwrite,s)?(this._kill(i,e),this._initProps(e,i,s,r)):(this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration)&&(F[e._gsTweenID]=!0),o)},n.render=function(t,e,i){var s,r,n,a,o=this._time,h=this._duration,l=this._rawPrevTime;if(t>=h)this._totalTime=this._time=h,this.ratio=this._ease._calcEnd?this._ease.getRatio(1):1,this._reversed||(s=!0,r="onComplete"),0===h&&(this._initted||!this.vars.lazy||i)&&(this._startTime===this._timeline._duration&&(t=0),(0===t||0>l||l===_&&"isPause"!==this.data)&&l!==t&&(i=!0,l>_&&(r="onReverseComplete")),this._rawPrevTime=a=!e||t||l===t?t:_);else if(1e-7>t)this._totalTime=this._time=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0,(0!==o||0===h&&l>0)&&(r="onReverseComplete",s=this._reversed),0>t&&(this._active=!1,0===h&&(this._initted||!this.vars.lazy||i)&&(l>=0&&(l!==_||"isPause"!==this.data)&&(i=!0),this._rawPrevTime=a=!e||t||l===t?t:_)),this._initted||(i=!0);
1728else if(this._totalTime=this._time=t,this._easeType){var u=t/h,p=this._easeType,f=this._easePower;(1===p||3===p&&u>=.5)&&(u=1-u),3===p&&(u*=2),1===f?u*=u:2===f?u*=u*u:3===f?u*=u*u*u:4===f&&(u*=u*u*u*u),this.ratio=1===p?1-u:2===p?u:.5>t/h?u/2:1-u/2}else this.ratio=this._ease.getRatio(t/h);if(this._time!==o||i){if(!this._initted){if(this._init(),!this._initted||this._gc)return;if(!i&&this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration))return this._time=this._totalTime=o,this._rawPrevTime=l,I.push(this),this._lazy=[t,e],void 0;this._time&&!s?this.ratio=this._ease.getRatio(this._time/h):s&&this._ease._calcEnd&&(this.ratio=this._ease.getRatio(0===this._time?0:1))}for(this._lazy!==!1&&(this._lazy=!1),this._active||!this._paused&&this._time!==o&&t>=0&&(this._active=!0),0===o&&(this._startAt&&(t>=0?this._startAt.render(t,e,i):r||(r="_dummyGS")),this.vars.onStart&&(0!==this._time||0===h)&&(e||this.vars.onStart.apply(this.vars.onStartScope||this,this.vars.onStartParams||y))),n=this._firstPT;n;)n.f?n.t[n.p](n.c*this.ratio+n.s):n.t[n.p]=n.c*this.ratio+n.s,n=n._next;this._onUpdate&&(0>t&&this._startAt&&t!==-1e-4&&this._startAt.render(t,e,i),e||(this._time!==o||s)&&this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||y)),r&&(!this._gc||i)&&(0>t&&this._startAt&&!this._onUpdate&&t!==-1e-4&&this._startAt.render(t,e,i),s&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[r]&&this.vars[r].apply(this.vars[r+"Scope"]||this,this.vars[r+"Params"]||y),0===h&&this._rawPrevTime===_&&a!==_&&(this._rawPrevTime=0))}},n._kill=function(t,e,i){if("all"===t&&(t=null),null==t&&(null==e||e===this.target))return this._lazy=!1,this._enabled(!1,!1);e="string"!=typeof e?e||this._targets||this.target:D.selector(e)||e;var s,r,n,a,o,h,l,_,u;if((f(e)||M(e))&&"number"!=typeof e[0])for(s=e.length;--s>-1;)this._kill(t,e[s])&&(h=!0);else{if(this._targets){for(s=this._targets.length;--s>-1;)if(e===this._targets[s]){o=this._propLookup[s]||{},this._overwrittenProps=this._overwrittenProps||[],r=this._overwrittenProps[s]=t?this._overwrittenProps[s]||{}:"all";break}}else{if(e!==this.target)return!1;o=this._propLookup,r=this._overwrittenProps=t?this._overwrittenProps||{}:"all"}if(o){if(l=t||o,_=t!==r&&"all"!==r&&t!==o&&("object"!=typeof t||!t._tempKill),i&&(D.onOverwrite||this.vars.onOverwrite)){for(n in l)o[n]&&(u||(u=[]),u.push(n));if(!W(this,i,e,u))return!1}for(n in l)(a=o[n])&&(a.pg&&a.t._kill(l)&&(h=!0),a.pg&&0!==a.t._overwriteProps.length||(a._prev?a._prev._next=a._next:a===this._firstPT&&(this._firstPT=a._next),a._next&&(a._next._prev=a._prev),a._next=a._prev=null),delete o[n]),_&&(r[n]=1);!this._firstPT&&this._initted&&this._enabled(!1,!1)}}return h},n.invalidate=function(){return this._notifyPluginsOfEnabled&&D._onPluginEvent("_onDisable",this),this._firstPT=this._overwrittenProps=this._startAt=this._onUpdate=null,this._notifyPluginsOfEnabled=this._active=this._lazy=!1,this._propLookup=this._targets?{}:[],A.prototype.invalidate.call(this),this.vars.immediateRender&&(this._time=-_,this.render(-this._delay)),this},n._enabled=function(t,e){if(o||a.wake(),t&&this._gc){var i,s=this._targets;if(s)for(i=s.length;--i>-1;)this._siblings[i]=G(s[i],this,!0);else this._siblings=G(this.target,this,!0)}return A.prototype._enabled.call(this,t,e),this._notifyPluginsOfEnabled&&this._firstPT?D._onPluginEvent(t?"_onEnable":"_onDisable",this):!1},D.to=function(t,e,i){return new D(t,e,i)},D.from=function(t,e,i){return i.runBackwards=!0,i.immediateRender=0!=i.immediateRender,new D(t,e,i)},D.fromTo=function(t,e,i,s){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,new D(t,e,s)},D.delayedCall=function(t,e,i,s,r){return new D(e,0,{delay:t,onComplete:e,onCompleteParams:i,onCompleteScope:s,onReverseComplete:e,onReverseCompleteParams:i,onReverseCompleteScope:s,immediateRender:!1,lazy:!1,useFrames:r,overwrite:0})},D.set=function(t,e){return new D(t,0,e)},D.getTweensOf=function(t,e){if(null==t)return[];t="string"!=typeof t?t:D.selector(t)||t;var i,s,r,n;if((f(t)||M(t))&&"number"!=typeof t[0]){for(i=t.length,s=[];--i>-1;)s=s.concat(D.getTweensOf(t[i],e));for(i=s.length;--i>-1;)for(n=s[i],r=i;--r>-1;)n===s[r]&&s.splice(i,1)}else for(s=G(t).concat(),i=s.length;--i>-1;)(s[i]._gc||e&&!s[i].isActive())&&s.splice(i,1);return s}
1728,D.killTweensOf=D.killDelayedCallsTo=function(t,e,i){"object"==typeof e&&(i=e,e=!1);for(var s=D.getTweensOf(t,e),r=s.length;--r>-1;)s[r]._kill(i,t)};var $=g("plugins.TweenPlugin",function(t,e){this._overwriteProps=(t||"").split(","),this._propName=this._overwriteProps[0],this._priority=e||0,this._super=$.prototype},!0);if(n=$.prototype,$.version="1.10.1",$.API=2,n._firstPT=null,n._addTween=function(t,e,i,s,r,n){var a,o;return null!=s&&(a="number"==typeof s||"="!==s.charAt(1)?Number(s)-i:parseInt(s.charAt(0)+"1",10)*Number(s.substr(2)))?(this._firstPT=o={_next:this._firstPT,t:t,p:e,s:i,c:a,f:"function"==typeof t[e],n:r||e,r:n},o._next&&(o._next._prev=o),o):void 0},n.setRatio=function(t){for(var e,i=this._firstPT,s=1e-6;i;)e=i.c*t+i.s,i.r?e=Math.round(e):s>e&&e>-s&&(e=0),i.f?i.t[i.p](e):i.t[i.p]=e,i=i._next},n._kill=function(t){var e,i=this._overwriteProps,s=this._firstPT;if(null!=t[this._propName])this._overwriteProps=[];else for(e=i.length;--e>-1;)null!=t[i[e]]&&i.splice(e,1);for(;s;)null!=t[s.n]&&(s._next&&(s._next._prev=s._prev),s._prev?(s._prev._next=s._next,s._prev=null):this._firstPT===s&&(this._firstPT=s._next)),s=s._next;return!1},n._roundProps=function(t,e){for(var i=this._firstPT;i;)(t[this._propName]||null!=i.n&&t[i.n.split(this._propName+"_").join("")])&&(i.r=e),i=i._next},D._onPluginEvent=function(t,e){var i,s,r,n,a,o=e._firstPT;if("_onInitAllProps"===t){for(;o;){for(a=o._next,s=r;s&&s.pr>o.pr;)s=s._next;(o._prev=s?s._prev:n)?o._prev._next=o:r=o,(o._next=s)?s._prev=o:n=o,o=a}o=e._firstPT=r}for(;o;)o.pg&&"function"==typeof o.t[t]&&o.t[t]()&&(i=!0),o=o._next;return i},$.activate=function(t){for(var e=t.length;--e>-1;)t[e].API===$.API&&(N[(new t[e])._propName]=t[e]);return!0},d.plugin=function(t){if(!(t&&t.propName&&t.init&&t.API))throw"illegal plugin definition.";var e,i=t.propName,s=t.priority||0,r=t.overwriteProps,n={init:"_onInitTween",set:"setRatio",kill:"_kill",round:"_roundProps",initAll:"_onInitAllProps"},a=g("plugins."+i.charAt(0).toUpperCase()+i.substr(1)+"Plugin",function(){$.call(this,i,s),this._overwriteProps=r||[]},t.global===!0),o=a.prototype=new $(i);o.constructor=a,a.API=t.API;for(e in n)"function"==typeof t[e]&&(o[n[e]]=t[e]);return a.version=t.version,$.activate([a]),a},s=t._gsQueue){for(r=0;s.length>r;r++)s[r]();for(n in c)c[n].func||t.console.log("GSAP encountered missing dependency: com.greensock."+n)}o=!1}}("undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window,"TweenMax");
1729// Avoid `console` errors in browsers that lack a console.
1730(function () {
1731    var method;
1732    var noop = function noop() { };
1733    var methods = [
1734        'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
1735        'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
1736        'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
1737        'timeStamp', 'trace', 'warn'
1738    ];
1739    var length = methods.length;
1740    var console = (window.console = window.console || {});
1741    while (length--) {
1742        method = methods[length];
1743        // Only stub undefined methods.
1744        if (!console[method]) {
1745            console[method] = noop;
1746        }
1747    }
1748}());
1749var Helper = new function () {
1750    // Has browser placeholder support
1751    this.nativePlaceholderSupport = function () {
1752        var i = document.createElement('input');
1753        return ('placeholder' in i);
1754    };
1755    //, other helper functions
1756};
1757//DONT ADD JQUERY PLUGINS HERE!!!! 
1758//# sourceMappingURL=plugins.js.map
1759/*!
1760 * jQuery Validation Plugin v1.13.1
1761 *
1762 * http://jqueryvalidation.org/
1763 *
1764 * Copyright (c) 2014 Jörn Zaefferer
1765 * Released under the MIT license
1766 */
1767(function( factory ) {
1768	if ( typeof define === "function" && define.amd ) {
1769		define( ["jquery"], factory );
1770	} else {
1771		factory( jQuery );
1772	}
1773}(function( $ ) {
1774
1775$.extend($.fn, {
1776	// http://jqueryvalidation.org/validate/
1777	validate: function( options ) {
1778
1779		// if nothing is selected, return nothing; can't chain anyway
1780		if ( !this.length ) {
1781			if ( options && options.debug && window.console ) {
1782				console.warn( "Nothing selected, can't validate, returning nothing." );
1783			}
1784			return;
1785		}
1786
1787		// check if a validator for this form was already created
1788		var validator = $.data( this[ 0 ], "validator" );
1789		if ( validator ) {
1790			return validator;
1791		}
1792
1793		// Add novalidate tag if HTML5.
1794		this.attr( "novalidate", "novalidate" );
1795
1796		validator = new $.validator( options, this[ 0 ] );
1797		$.data( this[ 0 ], "validator", validator );
1798
1799		if ( validator.settings.onsubmit ) {
1800
1801			this.validateDelegate( ":submit", "click", function( event ) {
1802				if ( validator.settings.submitHandler ) {
1803					validator.submitButton = event.target;
1804				}
1805				// allow suppressing validation by adding a cancel class to the submit button
1806				if ( $( event.target ).hasClass( "cancel" ) ) {
1807					validator.cancelSubmit = true;
1808				}
1809
1810				// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
1811				if ( $( event.target ).attr( "formnovalidate" ) !== undefined ) {
1812					validator.cancelSubmit = true;
1813				}
1814			});
1815
1816			// validate the form on submit
1817			this.submit( function( event ) {
1818				if ( validator.settings.debug ) {
1819					// prevent form submit to be able to see console output
1820					event.preventDefault();
1821				}
1822				function handle() {
1823					var hidden, result;
1824					if ( validator.settings.submitHandler ) {
1825						if ( validator.submitButton ) {
1826							// insert a hidden input as a replacement for the missing submit button
1827							hidden = $( "<input type='hidden'/>" )
1828								.attr( "name", validator.submitButton.name )
1829								.val( $( validator.submitButton ).val() )
1830								.appendTo( validator.currentForm );
1831						}
1832						result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
1833						if ( validator.submitButton ) {
1834							// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
1835							hidden.remove();
1836						}
1837						if ( result !== undefined ) {
1838							return result;
1839						}
1840						return false;
1841					}
1842					return true;
1843				}
1844
1845				// prevent submit for invalid forms or custom submit handlers
1846				if ( validator.cancelSubmit ) {
1847					validator.cancelSubmit = false;
1848					return handle();
1849				}
1850				if ( validator.form() ) {
1851					if ( validator.pendingRequest ) {
1852						validator.formSubmitted = true;
1853						return false;
1854					}
1855					return handle();
1856				} else {
1857					validator.focusInvalid();
1858					return false;
1859				}
1860			});
1861		}
1862
1863		return validator;
1864	},
1865	// http://jqueryvalidation.org/valid/
1866	valid: function() {
1867		var valid, validator;
1868
1869		if ( $( this[ 0 ] ).is( "form" ) ) {
1870			valid = this.validate().form();
1871		} else {
1872			valid = true;
1873			validator = $( this[ 0 ].form ).validate();
1874			this.each( function() {
1875				valid = validator.element( this ) && valid;
1876			});
1877		}
1878		return valid;
1879	},
1880	// attributes: space separated list of attributes to retrieve and remove
1881	removeAttrs: function( attributes ) {
1882		var result = {},
1883			$element = this;
1884		$.each( attributes.split( /\s/ ), function( index, value ) {
1885			result[ value ] = $element.attr( value );
1886			$element.removeAttr( value );
1887		});
1888		return result;
1889	},
1890	// http://jqueryvalidation.org/rules/
1891	rules: function( command, argument ) {
1892		var element = this[ 0 ],
1893			settings, staticRules, existingRules, data, param, filtered;
1894
1895		if ( command ) {
1896			settings = $.data( element.form, "validator" ).settings;
1897			staticRules = settings.rules;
1898			existingRules = $.validator.staticRules( element );
1899			switch ( command ) {
1900			case "add":
1901				$.extend( existingRules, $.validator.normalizeRule( argument ) );
1902				// remove messages from rules, but allow them to be set separately
1903				delete existingRules.messages;
1904				staticRules[ element.name ] = existingRules;
1905				if ( argument.messages ) {
1906					settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
1907				}
1908				break;
1909			case "remove":
1910				if ( !argument ) {
1911					delete staticRules[ element.name ];
1912					return existingRules;
1913				}
1914				filtered = {};
1915				$.each( argument.split( /\s/ ), function( index, method ) {
1916					filtered[ method ] = existingRules[ method ];
1917					delete existingRules[ method ];
1918					if ( method === "required" ) {
1919						$( element ).removeAttr( "aria-required" );
1920					}
1921				});
1922				return filtered;
1923			}
1924		}
1925
1926		data = $.validator.normalizeRules(
1927		$.extend(
1928			{},
1929			$.validator.classRules( element ),
1930			$.validator.attributeRules( element ),
1931			$.validator.dataRules( element ),
1932			$.validator.staticRules( element )
1933		), element );
1934
1935		// make sure required is at front
1936		if ( data.required ) {
1937			param = data.required;
1938			delete data.required;
1939			data = $.extend( { required: param }, data );
1940			$( element ).attr( "aria-required", "true" );
1941		}
1942
1943		// make sure remote is at back
1944		if ( data.remote ) {
1945			param = data.remote;
1946			delete data.remote;
1947			data = $.extend( data, { remote: param });
1948		}
1949
1950		return data;
1951	}
1952});
1953
1954// Custom selectors
1955$.extend( $.expr[ ":" ], {
1956	// http://jqueryvalidation.org/blank-selector/
1957	blank: function( a ) {
1958		return !$.trim( "" + $( a ).val() );
1959	},
1960	// http://jqueryvalidation.org/filled-selector/
1961	filled: function( a ) {
1962		return !!$.trim( "" + $( a ).val() );
1963	},
1964	// http://jqueryvalidation.org/unchecked-selector/
1965	unchecked: function( a ) {
1966		return !$( a ).prop( "checked" );
1967	}
1968});
1969
1970// constructor for validator
1971$.validator = function( options, form ) {
1972	this.settings = $.extend( true, {}, $.validator.defaults, options );
1973	this.currentForm = form;
1974	this.init();
1975};
1976
1977// http://jqueryvalidation.org/jQuery.validator.format/
1978$.validator.format = function( source, params ) {
1979	if ( arguments.length === 1 ) {
1980		return function() {
1981			var args = $.makeArray( arguments );
1982			args.unshift( source );
1983			return $.validator.format.apply( this, args );
1984		};
1985	}
1986	if ( arguments.length > 2 && params.constructor !== Array  ) {
1987		params = $.makeArray( arguments ).slice( 1 );
1988	}
1989	if ( params.constructor !== Array ) {
1990		params = [ params ];
1991	}
1992	$.each( params, function( i, n ) {
1993		source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
1994			return n;
1995		});
1996	});
1997	return source;
1998};
1999
2000$.extend( $.validator, {
2001
2002	defaults: {
2003		messages: {},
2004		groups: {},
2005		rules: {},
2006		errorClass: "error",
2007		validClass: "valid",
2008		errorElement: "label",
2009		focusCleanup: false,
2010		focusInvalid: true,
2011		errorContainer: $( [] ),
2012		errorLabelContainer: $( [] ),
2013		onsubmit: true,
2014		ignore: ":hidden",
2015		ignoreTitle: false,
2016		onfocusin: function( element ) {
2017			this.lastActive = element;
2018
2019			// Hide error label and remove error class on focus if enabled
2020			if ( this.settings.focusCleanup ) {
2021				if ( this.settings.unhighlight ) {
2022					this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.val
2022idClass );
2023				}
2024				this.hideThese( this.errorsFor( element ) );
2025			}
2026		},
2027		onfocusout: function( element ) {
2028			if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
2029				this.element( element );
2030			}
2031		},
2032		onkeyup: function( element, event ) {
2033			if ( event.which === 9 && this.elementValue( element ) === "" ) {
2034				return;
2035			} else if ( element.name in this.submitted || element === this.lastElement ) {
2036				this.element( element );
2037			}
2038		},
2039		onclick: function( element ) {
2040			// click on selects, radiobuttons and checkboxes
2041			if ( element.name in this.submitted ) {
2042				this.element( element );
2043
2044			// or option elements, check parent select in that case
2045			} else if ( element.parentNode.name in this.submitted ) {
2046				this.element( element.parentNode );
2047			}
2048		},
2049		highlight: function( element, errorClass, validClass ) {
2050			if ( element.type === "radio" ) {
2051				this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
2052			} else {
2053				$( element ).addClass( errorClass ).removeClass( validClass );
2054			}
2055		},
2056		unhighlight: function( element, errorClass, validClass ) {
2057			if ( element.type === "radio" ) {
2058				this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
2059			} else {
2060				$( element ).removeClass( errorClass ).addClass( validClass );
2061			}
2062		}
2063	},
2064
2065	// http://jqueryvalidation.org/jQuery.validator.setDefaults/
2066	setDefaults: function( settings ) {
2067		$.extend( $.validator.defaults, settings );
2068	},
2069
2070	messages: {
2071		required: "This field is required.",
2072		remote: "Please fix this field.",
2073		email: "Please enter a valid email address.",
2074		url: "Please enter a valid URL.",
2075		date: "Please enter a valid date.",
2076		dateISO: "Please enter a valid date ( ISO ).",
2077		number: "Please enter a valid number.",
2078		digits: "Please enter only digits.",
2079		creditcard: "Please enter a valid credit card number.",
2080		equalTo: "Please enter the same value again.",
2081		maxlength: $.validator.format( "Please enter no more than {0} characters." ),
2082		minlength: $.validator.format( "Please enter at least {0} characters." ),
2083		rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
2084		range: $.validator.format( "Please enter a value between {0} and {1}." ),
2085		max: $.validator.format( "Please enter a value less than or equal to {0}." ),
2086		min: $.validator.format( "Please enter a value greater than or equal to {0}." )
2087	},
2088
2089	autoCreateRanges: false,
2090
2091	prototype: {
2092
2093		init: function() {
2094			this.labelContainer = $( this.settings.errorLabelContainer );
2095			this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
2096			this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
2097			this.submitted = {};
2098			this.valueCache = {};
2099			this.pendingRequest = 0;
2100			this.pending = {};
2101			this.invalid = {};
2102			this.reset();
2103
2104			var groups = ( this.groups = {} ),
2105				rules;
2106			$.each( this.settings.groups, function( key, value ) {
2107				if ( typeof value === "string" ) {
2108					value = value.split( /\s/ );
2109				}
2110				$.each( value, function( index, name ) {
2111					groups[ name ] = key;
2112				});
2113			});
2114			rules = this.settings.rules;
2115			$.each( rules, function( key, value ) {
2116				rules[ key ] = $.validator.normalizeRule( value );
2117			});
2118
2119			function delegate( event ) {
2120				var validator = $.data( this[ 0 ].form, "validator" ),
2121					eventType = "on" + event.type.replace( /^validate/, "" ),
2122					settings = validator.settings;
2123				if ( settings[ eventType ] && !this.is( settings.ignore ) ) {
2124					settings[ eventType ].call( validator, this[ 0 ], event );
2125				}
2126			}
2127			$( this.currentForm )
2128				.validateDelegate( ":text, [type='password'], [type='file'], select, textarea, " +
2129					"[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
2130					"[type='email'], [type='datetime'], [type='date'], [type='month'], " +
2131					"[type='week'], [type='time'], [type='datetime-local'], " +
2132					"[type='range'], [type='color'], [type='radio'], [type='checkbox']",
2133					"focusin focusout keyup", delegate)
2134				// Support: Chrome, oldIE
2135				// "select" is provided as event.target when clicking a option
2136				.validateDelegate("select, option, [type='radio'], [type='checkbox']", "click", delegate);
2137
2138			if ( this.settings.invalidHandler ) {
2139				$( this.currentForm ).bind( "invalid-form.validate", this.settings.invalidHandler );
2140			}
2141
2142			// Add aria-required to any Static/Data/Class required fields before first validation
2143			// Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html
2144			$( this.currentForm ).find( "[required], [data-rule-required], .required" ).attr( "aria-required", "true" );
2145		},
2146
2147		// http://jqueryvalidation.org/Validator.form/
2148		form: function() {
2149			this.checkForm();
2150			$.extend( this.submitted, this.errorMap );
2151			this.invalid = $.extend({}, this.errorMap );
2152			if ( !this.valid() ) {
2153				$( this.currentForm ).triggerHandler( "invalid-form", [ this ]);
2154			}
2155			this.showErrors();
2156			return this.valid();
2157		},
2158
2159		checkForm: function() {
2160			this.prepareForm();
2161			for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
2162				this.check( elements[ i ] );
2163			}
2164			return this.valid();
2165		},
2166
2167		// http://jqueryvalidation.org/Validator.element/
2168		element: function( element ) {
2169			var cleanElement = this.clean( element ),
2170				checkElement = this.validationTargetFor( cleanElement ),
2171				result = true;
2172
2173			this.lastElement = checkElement;
2174
2175			if ( checkElement === undefined ) {
2176				delete this.invalid[ cleanElement.name ];
2177			} else {
2178				this.prepareElement( checkElement );
2179				this.currentElements = $( checkElement );
2180
2181				result = this.check( checkElement ) !== false;
2182				if ( result ) {
2183					delete this.invalid[ checkElement.name ];
2184				} else {
2185					this.invalid[ checkElement.name ] = true;
2186				}
2187			}
2188			// Add aria-invalid status for screen readers
2189			$( element ).attr( "aria-invalid", !result );
2190
2191			if ( !this.numberOfInvalids() ) {
2192				// Hide error containers on last error
2193				this.toHide = this.toHide.add( this.containers );
2194			}
2195			this.showErrors();
2196			return result;
2197		},
2198
2199		// http://jqueryvalidation.org/Validator.showErrors/
2200		showErrors: function( errors ) {
2201			if ( errors ) {
2202				// add items to error list and map
2203				$.extend( this.errorMap, errors );
2204				this.errorList = [];
2205				for ( var name in errors ) {
2206					this.errorList.push({
2207						message: errors[ name ],
2208						element: this.findByName( name )[ 0 ]
2209					});
2210				}
2211				// remove items from success list
2212				this.successList = $.grep( this.successList, function( element ) {
2213					return !( element.name in errors );
2214				});
2215			}
2216			if ( this.settings.showErrors ) {
2217				this.settings.showErrors.call( this, this.errorMap, this.errorList );
2218			} else {
2219				this.defaultShowErrors();
2220			}
2221		},
2222
2223		// http://jqueryvalidation.org/Validator.resetForm/
2224		resetForm: function() {
2225			if ( $.fn.resetForm ) {
2226				$( this.currentForm ).resetForm();
2227			}
2228			this.submitted = {};
2229			this.lastElement = null;
2230			this.prepareForm();
2231			this.hideErrors();
2232			this.elements()
2233					.removeClass( this.settings.errorClass )
2234					.removeData( "previousValue" )
2235					.removeAttr( "aria-invalid" );
2236		},
2237
2238		numberOfInvalids: function() {
2239			return this.objectLength( this.invalid );
2240		},
2241
2242		objectLength: function( obj ) {
2243			/* jshint unused: false */
2244			var count = 0,
2245				i;
2246			for ( i in obj ) {
2247				count++;
2248			}
2249			return count;
2250		},
2251
2252		hideErrors: function() {
2253			this.hideThese( this.toHide );
2254		},
2255
2256		hideThese: function( errors ) {
2257			errors.not( this.containers ).text( "" );
2258			this.addWrapper( errors ).hide();
2259		},
2260
2261		valid: function() {
2262			return this.size() === 0;
2263		},
2264
2265		size: function() {
2266			return this.errorList.length;
2267		},
2268
2269		focusInvalid: function() {
2270			if ( this.settings.focusInvalid ) {
2271				try {
2272					$( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [])
2273					.filter( ":visible" )
2274					.focus()
2275					// manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
2276					.trigger( "focusin" );
2277				} catch ( e ) {
2278					// ignore IE throwing errors when focusing hidden elements
2279				}
2280			}
2281		},
2282
2283		findLastActive: function() {
2284			var lastActive = this.lastActive;
2285			return lastActive && $.grep( this.errorList, function( n ) {
2286				return n.element.name === lastActive.name;
2287			}).length === 1 && lastActive;
2288		},
2289
2290		elements: function() {
2291			var validator = this,
2292				rulesCache = {};
2293
2294			// select all valid inputs inside the form (no submit or reset buttons)
2295			return $( this.currentForm )
2296			.find( "input, select, textarea" )
2297			.not( ":submit, :reset, :image, [disabled], [readonly]" )
2298			.not( this.settings.ignore )
2299			.filter( function() {
2300				if ( !this.name && validator.settings.debug && window.console ) {
2301					console.error( "%o has no name assigned", this );
2302				}
2303
2304				// select only the first element for each name, and only those with rules specified
2305				if ( this.name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
2306					return false;
2307				}
2308
2309				rulesCache[ this.name ] = true;
2310				return true;
2311			});
2312		},
2313
2314		clean: function( selector ) {
2315			return $( selector )[ 0 ];
2316		},
2317
2318		errors: function() {
2319			var errorClass = this.settings.errorClass.split( " " ).join( "." );
2320			return $( this.settings.errorElement + "." + errorClass, this.errorContext );
2321		},
2322
2323		reset: function() {
2324			this.successList = [];
2325			this.errorList = [];
2326			this.errorMap = {};
2327			this.toShow = $( [] );
2328			this.toHide = $( [] );
2329			this.currentElements = $( [] );
2330		},
2331
2332		prepareForm: function() {
2333			this.reset();
2334			this.toHide = this.errors().add( this.containers );
2335		},
2336
2337		prepareElement: function( element ) {
2338			this.reset();
2339			this.toHide = this.errorsFor( element );
2340		},
2341
2342		elementValue: function( element ) {
2343			var val,
2344				$element = $( element ),
2345				type = element.type;
2346
2347			if ( type === "radio" || type === "checkbox" ) {
2348				return $( "input[name='" + element.name + "']:checked" ).val();
2349			} else if ( type === "number" && typeof element.validity !== "undefined" ) {
2350				return element.validity.badInput ? false : $element.val();
2351			}
2352
2353			val = $element.val();
2354			if ( typeof val === "string" ) {
2355				return val.replace(/\r/g, "" );
2356			}
2357			return val;
2358		},
2359
2360		check: function( element ) {
2361			element = this.validationTargetFor( this.clean( element ) );
2362
2363			var rules = $( element ).rules(),
2364				rulesCount = $.map( rules, function( n, i ) {
2365					return i;
2366				}).length,
2367				dependencyMismatch = false,
2368				val = this.elementValue( element ),
2369				result, method, rule;
2370
2371			for ( method in rules ) {
2372				rule = { method: method, parameters: rules[ method ] };
2373				try {
2374
2375					result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
2376
2377					// if a method indicates that the field is optional and therefore valid,
2378					// don't mark it as valid when there are no other rules
2379					if ( result === "dependency-mismatch" && rulesCount === 1 ) {
2380						dependencyMismatch = true;
2381						continue;
2382					}
2383					dependencyMismatch = false;
2384
2385					if ( result === "pending" ) {
2386						this.toHide = this.toHide.not( this.errorsFor( element ) );
2387						return;
2388					}
2389
2390					if ( !result ) {
2391						this.formatAndAdd( element, rule );
2392						return false;
2393					}
2394				} catch ( e ) {
2395					if ( this.settings.debug && window.console ) {
2396						console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
2397					}
2398					throw e;
2399				}
2400			}
2401			if ( dependencyMismatch ) {
2402				return;
2403			}
2404			if ( this.objectLength( rules ) ) {
2405				this.successList.push( element );
2406			}
2407			return true;
2408		},
2409
2410		// return the custom message for the given element and validation method
2411		// specified in the element's HTML5 data attribute
2412		// return the generic message if present and no method specific message is present
2413		customDataMessage: function( element, method ) {
2414			return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
2415				method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
2416		},
2417
2418		// return the custom message for the given element name and validation method
2419		customMessage: function( name, method ) {
2420			var m = this.settings.messages[ name ];
2421			return m && ( m.constructor === String ? m : m[ method ]);
2422		},
2423
2424		// return the first defined argument, allowing empty strings
2425		findDefined: function() {
2426			for ( var i = 0; i < arguments.length; i++) {
2427				if ( arguments[ i ] !== undefined ) {
2428					return arguments[ i ];
2429				}
2430			}
2431			return undefined;
2432		},
2433
2434		defaultMessage: function( element, method ) {
2435			return this.findDefined(
2436				this.customMessage( element.name, method ),
2437				this.customDataMessage( element, method ),
2438				// title is never undefined, so handle empty string as undefined
2439				!this.settings.ignoreTitle && element.title || undefined,
2440				$.validator.messages[ method ],
2441				"<strong>Warning: No message defined for " + element.name + "</strong>"
2442			);
2443		},
2444
2445		formatAndAdd: function( element, rule ) {
2446			var message = this.defaultMessage( element, rule.method ),
2447				theregex = /\$?\{(\d+)\}/g;
2448			if ( typeof message === "function" ) {
2449				message = message.call( this, rule.parameters, element );
2450			} else if ( theregex.test( message ) ) {
2451				message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
2452			}
2453			this.errorList.push({
2454				message: message,
2455				element: element,
2456				method: rule.method
2457			});
2458
2459			this.errorMap[ element.name ] = message;
2460			this.submitted[ element.name ] = message;
2461		},
2462
2463		addWrapper: function( toToggle ) {
2464			if ( this.settings.wrapper ) {
2465				toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
2466			}
2467			return toToggle;
2468		},
2469
2470		defaultShowErrors: function() {
2471			var i, elements, error;
2472			for ( i = 0; this.errorList[ i ]; i++ ) {
2473				error = this.errorList[ i ];
2474				if ( this.settings.highlight ) {
2475					this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.val
2475idClass );
2476				}
2477				this.showLabel( error.element, error.message );
2478			}
2479			if ( this.errorList.length ) {
2480				this.toShow = this.toShow.add( this.containers );
2481			}
2482			if ( this.settings.success ) {
2483				for ( i = 0; this.successList[ i ]; i++ ) {
2484					this.showLabel( this.successList[ i ] );
2485				}
2486			}
2487			if ( this.settings.unhighlight ) {
2488				for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
2489					this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
2490				}
2491			}
2492			this.toHide = this.toHide.not( this.toShow );
2493			this.hideErrors();
2494			this.addWrapper( this.toShow ).show();
2495		},
2496
2497		validElements: function() {
2498			return this.currentElements.not( this.invalidElements() );
2499		},
2500
2501		invalidElements: function() {
2502			return $( this.errorList ).map(function() {
2503				return this.element;
2504			});
2505		},
2506
2507		showLabel: function( element, message ) {
2508			var place, group, errorID,
2509				error = this.errorsFor( element ),
2510				elementID = this.idOrName( element ),
2511				describedBy = $( element ).attr( "aria-describedby" );
2512			if ( error.length ) {
2513				// refresh error/success class
2514				error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
2515				// replace message on existing label
2516				error.html( message );
2517			} else {
2518				// create error element
2519				error = $( "<" + this.settings.errorElement + ">" )
2520					.attr( "id", elementID + "-error" )
2521					.addClass( this.settings.errorClass )
2522					.html( message || "" );
2523
2524				// Maintain reference to the element to be placed into the DOM
2525				place = error;
2526				if ( this.settings.wrapper ) {
2527					// make sure the element is visible, even in IE
2528					// actually showing the wrapped element is handled elsewhere
2529					place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
2530				}
2531				if ( this.labelContainer.length ) {
2532					this.labelContainer.append( place );
2533				} else if ( this.settings.errorPlacement ) {
2534					this.settings.errorPlacement( place, $( element ) );
2535				} else {
2536					place.insertAfter( element );
2537				}
2538
2539				// Link error back to the element
2540				if ( error.is( "label" ) ) {
2541					// If the error is a label, then associate using 'for'
2542					error.attr( "for", elementID );
2543				} else if ( error.parents( "label[for='" + elementID + "']" ).length === 0 ) {
2544					// If the element is not a child of an associated label, then it's necessary
2545					// to explicitly apply aria-describedby
2546
2547					errorID = error.attr( "id" ).replace( /(:|\.|\[|\])/g, "\\$1");
2548					// Respect existing non-error aria-describedby
2549					if ( !describedBy ) {
2550						describedBy = errorID;
2551					} else if ( !describedBy.match( new RegExp( "\\b" + errorID + "\\b" ) ) ) {
2552						// Add to end of list if not already present
2553						describedBy += " " + errorID;
2554					}
2555					$( element ).attr( "aria-describedby", describedBy );
2556
2557					// If this element is grouped, then assign to all elements in the same group
2558					group = this.groups[ element.name ];
2559					if ( group ) {
2560						$.each( this.groups, function( name, testgroup ) {
2561							if ( testgroup === group ) {
2562								$( "[name='" + name + "']", this.currentForm )
2563									.attr( "aria-describedby", error.attr( "id" ) );
2564							}
2565						});
2566					}
2567				}
2568			}
2569			if ( !message && this.settings.success ) {
2570				error.text( "" );
2571				if ( typeof this.settings.success === "string" ) {
2572					error.addClass( this.settings.success );
2573				} else {
2574					this.settings.success( error, element );
2575				}
2576			}
2577			this.toShow = this.toShow.add( error );
2578		},
2579
2580		errorsFor: function( element ) {
2581			var name = this.idOrName( element ),
2582				describer = $( element ).attr( "aria-describedby" ),
2583				selector = "label[for='" + name + "'], label[for='" + name + "'] *";
2584
2585			// aria-describedby should directly reference the error element
2586			if ( describer ) {
2587				selector = selector + ", #" + describer.replace( /\s+/g, ", #" );
2588			}
2589			return this
2590				.errors()
2591				.filter( selector );
2592		},
2593
2594		idOrName: function( element ) {
2595			return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.i
vendor: 7,280 bytes, lines 2595-2848
2595d || element.name );
2596		},
2597
2598		validationTargetFor: function( element ) {
2599
2600			// If radio/checkbox, validate first element in group instead
2601			if ( this.checkable( element ) ) {
2602				element = this.findByName( element.name );
2603			}
2604
2605			// Always apply ignore filter
2606			return $( element ).not( this.settings.ignore )[ 0 ];
2607		},
2608
2609		checkable: function( element ) {
2610			return ( /radio|checkbox/i ).test( element.type );
2611		},
2612
2613		findByName: function( name ) {
2614			return $( this.currentForm ).find( "[name='" + name + "']" );
2615		},
2616
2617		getLength: function( value, element ) {
2618			switch ( element.nodeName.toLowerCase() ) {
2619			case "select":
2620				return $( "option:selected", element ).length;
2621			case "input":
2622				if ( this.checkable( element ) ) {
2623					return this.findByName( element.name ).filter( ":checked" ).length;
2624				}
2625			}
2626			return value.length;
2627		},
2628
2629		depend: function( param, element ) {
2630			return this.dependTypes[typeof param] ? this.dependTypes[typeof param]( param, element ) : true;
2631		},
2632
2633		dependTypes: {
2634			"boolean": function( param ) {
2635				return param;
2636			},
2637			"string": function( param, element ) {
2638				return !!$( param, element.form ).length;
2639			},
2640			"function": function( param, element ) {
2641				return param( element );
2642			}
2643		},
2644
2645		optional: function( element ) {
2646			var val = this.elementValue( element );
2647			return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
2648		},
2649
2650		startRequest: function( element ) {
2651			if ( !this.pending[ element.name ] ) {
2652				this.pendingRequest++;
2653				this.pending[ element.name ] = true;
2654			}
2655		},
2656
2657		stopRequest: function( element, valid ) {
2658			this.pendingRequest--;
2659			// sometimes synchronization fails, make sure pendingRequest is never < 0
2660			if ( this.pendingRequest < 0 ) {
2661				this.pendingRequest = 0;
2662			}
2663			delete this.pending[ element.name ];
2664			if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
2665				$( this.currentForm ).submit();
2666				this.formSubmitted = false;
2667			} else if (!valid && this.pendingRequest === 0 && this.formSubmitted ) {
2668				$( this.currentForm ).triggerHandler( "invalid-form", [ this ]);
2669				this.formSubmitted = false;
2670			}
2671		},
2672
2673		previousValue: function( element ) {
2674			return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
2675				old: null,
2676				valid: true,
2677				message: this.defaultMessage( element, "remote" )
2678			});
2679		}
2680
2681	},
2682
2683	classRuleSettings: {
2684		required: { required: true },
2685		email: { email: true },
2686		url: { url: true },
2687		date: { date: true },
2688		dateISO: { dateISO: true },
2689		number: { number: true },
2690		digits: { digits: true },
2691		creditcard: { creditcard: true }
2692	},
2693
2694	addClassRules: function( className, rules ) {
2695		if ( className.constructor === String ) {
2696			this.classRuleSettings[ className ] = rules;
2697		} else {
2698			$.extend( this.classRuleSettings, className );
2699		}
2700	},
2701
2702	classRules: function( element ) {
2703		var rules = {},
2704			classes = $( element ).attr( "class" );
2705
2706		if ( classes ) {
2707			$.each( classes.split( " " ), function() {
2708				if ( this in $.validator.classRuleSettings ) {
2709					$.extend( rules, $.validator.classRuleSettings[ this ]);
2710				}
2711			});
2712		}
2713		return rules;
2714	},
2715
2716	attributeRules: function( element ) {
2717		var rules = {},
2718			$element = $( element ),
2719			type = element.getAttribute( "type" ),
2720			method, value;
2721
2722		for ( method in $.validator.methods ) {
2723
2724			// support for <input required> in both html5 and older browsers
2725			if ( method === "required" ) {
2726				value = element.getAttribute( method );
2727				// Some browsers return an empty string for the required attribute
2728				// and non-HTML5 browsers might have required="" markup
2729				if ( value === "" ) {
2730					value = true;
2731				}
2732				// force non-HTML5 browsers to return bool
2733				value = !!value;
2734			} else {
2735				value = $element.attr( method );
2736			}
2737
2738			// convert the value to a number for number inputs, and for text for backwards compability
2739			// allows type="date" and others to be compared as strings
2740			if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
2741				value = Number( value );
2742			}
2743
2744			if ( value || value === 0 ) {
2745				rules[ method ] = value;
2746			} else if ( type === method && type !== "range" ) {
2747				// exception: the jquery validate 'range' method
2748				// does not test for the html5 'range' type
2749				rules[ method ] = true;
2750			}
2751		}
2752
2753		// maxlength may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
2754		if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
2755			delete rules.maxlength;
2756		}
2757
2758		return rules;
2759	},
2760
2761	dataRules: function( element ) {
2762		var method, value,
2763			rules = {}, $element = $( element );
2764		for ( method in $.validator.methods ) {
2765			value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
2766			if ( value !== undefined ) {
2767				rules[ method ] = value;
2768			}
2769		}
2770		return rules;
2771	},
2772
2773	staticRules: function( element ) {
2774		var rules = {},
2775			validator = $.data( element.form, "validator" );
2776
2777		if ( validator.settings.rules ) {
2778			rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
2779		}
2780		return rules;
2781	},
2782
2783	normalizeRules: function( rules, element ) {
2784		// handle dependency check
2785		$.each( rules, function( prop, val ) {
2786			// ignore rule when param is explicitly false, eg. required:false
2787			if ( val === false ) {
2788				delete rules[ prop ];
2789				return;
2790			}
2791			if ( val.param || val.depends ) {
2792				var keepRule = true;
2793				switch ( typeof val.depends ) {
2794				case "string":
2795					keepRule = !!$( val.depends, element.form ).length;
2796					break;
2797				case "function":
2798					keepRule = val.depends.call( element, element );
2799					break;
2800				}
2801				if ( keepRule ) {
2802					rules[ prop ] = val.param !== undefined ? val.param : true;
2803				} else {
2804					delete rules[ prop ];
2805				}
2806			}
2807		});
2808
2809		// evaluate parameters
2810		$.each( rules, function( rule, parameter ) {
2811			rules[ rule ] = $.isFunction( parameter ) ? parameter( element ) : parameter;
2812		});
2813
2814		// clean number parameters
2815		$.each([ "minlength", "maxlength" ], function() {
2816			if ( rules[ this ] ) {
2817				rules[ this ] = Number( rules[ this ] );
2818			}
2819		});
2820		$.each([ "rangelength", "range" ], function() {
2821			var parts;
2822			if ( rules[ this ] ) {
2823				if ( $.isArray( rules[ this ] ) ) {
2824					rules[ this ] = [ Number( rules[ this ][ 0 ]), Number( rules[ this ][ 1 ] ) ];
2825				} else if ( typeof rules[ this ] === "string" ) {
2826					parts = rules[ this ].replace(/[\[\]]/g, "" ).split( /[\s,]+/ );
2827					rules[ this ] = [ Number( parts[ 0 ]), Number( parts[ 1 ] ) ];
2828				}
2829			}
2830		});
2831
2832		if ( $.validator.autoCreateRanges ) {
2833			// auto-create ranges
2834			if ( rules.min != null && rules.max != null ) {
2835				rules.range = [ rules.min, rules.max ];
2836				delete rules.min;
2837				delete rules.max;
2838			}
2839			if ( rules.minlength != null && rules.maxlength != null ) {
2840				rules.rangelength = [ rules.minlength, rules.maxlength ];
2841				delete rules.minlength;
2842				delete rules.maxlength;
2843			}
2844		}
2845
2846		return rules;
2847	},
2848
2849	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
2850	normalizeRule: function( data ) {
2851		if ( typeof data === "string" ) {
2852			var transformed = {};
2853			$.each( data.split( /\s/ ), function() {
2854				transformed[ this ] = true;
2855			});
2856			data = transformed;
2857		}
2858		return data;
2859	},
2860
2861	// http://jqueryvalidation.org/jQuery.validator.addMethod/
2862	addMethod: function( name, method, message ) {
2863		$.validator.methods[ name ] = method;
2864		$.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
2865		if ( method.length < 3 ) {
2866			$.validator.addClassRules( name, $.validator.normalizeRule( name ) );
2867		}
2868	},
2869
2870	methods: {
2871
2872		// http://jqueryvalidation.org/required-method/
2873		required: function( value, element, param ) {
2874			// check if dependency is met
2875			if ( !this.depend( param, element ) ) {
2876				return "dependency-mismatch";
2877			}
2878			if ( element.nodeName.toLowerCase() === "select" ) {
2879				// could be an array for select-multiple or a string, both are fine this way
2880				var val = $( element ).val();
2881				return val && val.length > 0;
2882			}
2883			if ( this.checkable( element ) ) {
2884				return this.getLength( value, element ) > 0;
2885			}
2886			return $.trim( value ).length > 0;
2887		},
2888
2889		// http://jqueryvalidation.org/email-method/
2890		email: function( value, element ) {
2891			// From http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-%28type=email%29
2892			// Retrieved 2014-01-14
2893			// If you have a problem with this implementation, report a bug against the above spec
2894			// Or use custom methods to implement your own email validation
2895			return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );
2896		},
2897
2898		// http://jqueryvalidation.org/url-method/
2899		url: function( value, element ) {
2900			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
2901			return this.optional( element ) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test( value );
2902		},
2903
2904		// http://jqueryvalidation.org/date-method/
2905		date: function( value, element ) {
2906			return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
2907		},
2908
2909		// http://jqueryvalidation.org/dateISO-method/
2910		dateISO: function( value, element ) {
2911			return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
2912		},
2913
2914		// http://jqueryvalidation.org/number-method/
2915		number: function( value, element ) {
2916			return this.optional( element ) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
2917		},
2918
2919		// http://jqueryvalidation.org/digits-method/
2920		digits: function( value, element ) {
2921			return this.optional( element ) || /^\d+$/.test( value );
2922		},
2923
2924		// http://jqueryvalidation.org/creditcard-method/
2925		// based on http://en.wikipedia.org/wiki/Luhn/
2926		creditcard: function( value, element ) {
2927			if ( this.optional( element ) ) {
2928				return "dependency-mismatch";
2929			}
2930			// accept only spaces, digits and dashes
2931			if ( /[^0-9 \-]+/.test( value ) ) {
2932				return false;
2933			}
2934			var nCheck = 0,
2935				nDigit = 0,
2936				bEven = false,
2937				n, cDigit;
2938
2939			value = value.replace( /\D/g, "" );
2940
2941			// Basing min and max length on
2942			// http://developer.ean.com/general_info/Valid_Credit_Card_Types
2943			if ( value.length < 13 || value.length > 19 ) {
2944				return false;
2945			}
2946
2947			for ( n = value.length - 1; n >= 0; n--) {
2948				cDigit = value.charAt( n );
2949				nDigit = parseInt( cDigit, 10 );
2950				if ( bEven ) {
2951					if ( ( nDigit *= 2 ) > 9 ) {
2952						nDigit -= 9;
2953					}
2954				}
2955				nCheck += nDigit;
2956				bEven = !bEven;
2957			}
2958
2959			return ( nCheck % 10 ) === 0;
2960		},
2961
2962		// http://jqueryvalidation.org/minlength-method/
2963		minlength: function( value, element, param ) {
2964			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
2965			return this.optional( element ) || length >= param;
2966		},
2967
2968		// http://jqueryvalidation.org/maxlength-method/
2969		maxlength: function( value, element, param ) {
2970			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
2971			return this.optional( element ) || length <= param;
2972		},
2973
2974		// http://jqueryvalidation.org/rangelength-method/
2975		rangelength: function( value, element, param ) {
2976			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
2977			return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
2978		},
2979
2980		// http://jqueryvalidation.org/min-method/
2981		min: function( value, element, param ) {
2982			return this.optional( element ) || value >= param;
2983		},
2984
2985		// http://jqueryvalidation.org/max-method/
2986		max: function( value, element, param ) {
2987			return this.optional( element ) || value <= param;
2988		},
2989
2990		// http://jqueryvalidation.org/range-method/
2991		range: function( value, element, param ) {
2992			return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
2993		},
2994
2995		// http://jqueryvalidation.org/equalTo-method/
2996		equalTo: function( value, element, param ) {
2997			// bind to the blur event of the target in order to revalidate whenever the target field is updated
2998			// TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
2999			var target = $( param );
3000			if ( this.settings.onfocusout ) {
3001				target.unbind( ".validate-equalTo" ).bind( "blur.validate-equalTo", function() {
3002					$( element ).valid();
3003				});
3004			}
3005			return value === target.val();
3006		},
3007
3008		// http://jqueryvalidation.org/remote-method/
3009		remote: function( value, element, param ) {
3010			if ( this.optional( element ) ) {
3011				return "dependency-mismatch";
3012			}
3013
3014			var previous = this.previousValue( element ),
3015				validator, data;
3016
3017			if (!this.settings.messages[ element.name ] ) {
3018				this.settings.messages[ element.name ] = {};
3019			}
3020			previous.originalMessage = this.settings.messages[ element.name ].remote;
3021			this.settings.messages[ element.name ].remote = previous.message;
3022
3023			param = typeof param === "string" && { url: param } || param;
3024
3025			if ( previous.old === value ) {
3026				return previous.valid;
3027			}
3028
3029			previous.old = value;
3030			validator = this;
3031			this.startRequest( element );
3032			data = {};
3033			data[ element.name ] = value;
3034			$.ajax( $.extend( true, {
3035				url: param,
3036				mode: "abort",
3037				port: "validate" + element.name,
3038				dataType: "json",
3039				data: data,
3040				context: validator.currentForm,
3041				success: function( response ) {
3042					var valid = response === true || response === "true",
3043						errors, message, submitted;
3044
3045					validator.settings.messages[ element.name ].remote = previous.originalMessage;
3046					if ( valid ) {
3047						submitted = validator.formSubmitted;
3048						validator.prepareElement( element );
3049						validator.formSubmitted = submitted;
3050						validator.successList.push( element );
3051						delete validator.invalid[ element.name ];
3052						validator.showErrors();
3053					} else {
3054						errors = {};
3055						message = response || validator.defaultMessage( element, "remote" );
3056						errors[ element.name ] = previous.message = $.isFunction( message ) ? message( value ) : message;
3057						validator.invalid[ element.name ] = true;
3058						validator.showErrors( errors );
3059					}
3060					previous.valid = valid;
3061					validator.stopRequest( element, valid );
3062				}
3063			}, param ) );
3064			return "pending";
3065		}
3066
3067	}
3068
3069});
3070
3071$.format = function deprecated() {
3072	throw "$.format has been deprecated. Please use $.validator.format instead.";
3073};
3074
3075// ajax mode: abort
3076// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
3077// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
3078
3079var pendingRequests = {},
3080	ajax;
3081// Use a prefilter if available (1.5+)
3082if ( $.ajaxPrefilter ) {
3083	$.ajaxPrefilter(function( settings, _, xhr ) {
3084		var port = settings.port;
3085		if ( settings.mode === "abort" ) {
3086			if ( pendingRequests[port] ) {
3087				pendingRequests[port].abort();
3088			}
3089			pendingRequests[port] = xhr;
3090		}
3091	});
3092} else {
3093	// Proxy ajax
3094	ajax = $.ajax;
3095	$.ajax = function( settings ) {
3096		var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
3097			port = ( "port" in settings ? settings : $.ajaxSettings ).port;
3098		if ( mode === "abort" ) {
3099			if ( pendingRequests[port] ) {
3100				pendingRequests[port].abort();
3101			}
3102			pendingRequests[port] = ajax.apply(this, arguments);
3103			return pendingRequests[port];
3104		}
3105		return ajax.apply(this, arguments);
3106	};
3107}
3108
3109// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
3110// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
3111
3112$.extend($.fn, {
3113	validateDelegate: function( delegate, type, handler ) {
3114		return this.bind(type, function( event ) {
3115			var target = $(event.target);
3116			if ( target.is(delegate) ) {
3117				return handler.apply(target, arguments);
3118			}
3119		});
3120	}
3121});
3122
3123}));
3124/*!
3125** Unobtrusive validation support library for jQuery and jQuery Validate
3126** Copyright (C) Microsoft Corporation. All rights reserved.
3127*/
3128
3129/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
3130/*global document: false, jQuery: false */
3131
3132(function ($) {
3133    var $jQval = $.validator,
3134        adapters,
3135        data_validation = "unobtrusiveValidation";
3136
3137    function setValidationValues(options, ruleName, value) {
3138        options.rules[ruleName] = value;
3139        if (options.message) {
3140            options.messages[ruleName] = options.message;
3141        }
3142    }
3143
3144    function splitAndTrim(value) {
3145        return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
3146    }
3147
3148    function escapeAttributeValue(value) {
3149        // As mentioned on http://api.jquery.com/category/selectors/
3150        return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
3151    }
3152
3153    function getModelPrefix(fieldName) {
3154        return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
3155    }
3156
3157    function appendModelPrefix(value, prefix) {
3158        if (value.indexOf("*.") === 0) {
3159            value = value.replace("*.", prefix);
3160        }
3161        return value;
3162    }
3163
3164    function onError(error, inputElement) {  // 'this' is the form element
3165        var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
3166            replaceAttrValue = container.attr("data-valmsg-replace"),
3167            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
3168
3169        container.removeClass("field-validation-valid").addClass("field-validation-error");
3170        error.data("unobtrusiveContainer", container);
3171
3172        if (replace) {
3173            container.empty();
3174            error.removeClass("input-validation-error").appendTo(container);
3175        }
3176        else {
3177            error.hide();
3178        }
3179    }
3180
3181    function onErrors(event, validator) {  // 'this' is the form element
3182        var container = $(this).find("[data-valmsg-summary=true]"),
3183            list = container.find("ul");
3184
3185        if (list && list.length && validator.errorList.length) {
3186            list.empty();
vendor: 15,714 bytes, lines 3187-3530
3187            container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
3188
3189            $.each(validator.errorList, function () {
3190                $("<li />").html(this.message).appendTo(list);
3191            });
3192        }
3193    }
3194
3195    function onSuccess(error) {  // 'this' is the form element
3196        var container = error.data("unobtrusiveContainer"),
3197            replaceAttrValue = container.attr("data-valmsg-replace"),
3198            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
3199
3200        if (container) {
3201            container.addClass("field-validation-valid").removeClass("field-validation-error");
3202            error.removeData("unobtrusiveContainer");
3203
3204            if (replace) {
3205                container.empty();
3206            }
3207        }
3208    }
3209
3210    function onReset(event) {  // 'this' is the form element
3211        var $form = $(this);
3212        $form.data("validator").resetForm();
3213        $form.find(".validation-summary-errors")
3214            .addClass("validation-summary-valid")
3215            .removeClass("validation-summary-errors");
3216        $form.find(".field-validation-error")
3217            .addClass("field-validation-valid")
3218            .removeClass("field-validation-error")
3219            .removeData("unobtrusiveContainer")
3220            .find(">*")  // If we were using valmsg-replace, get the underlying error
3221                .removeData("unobtrusiveContainer");
3222    }
3223
3224    function validationInfo(form) {
3225        var $form = $(form),
3226            result = $form.data(data_validation),
3227            onResetProxy = $.proxy(onReset, form);
3228
3229        if (!result) {
3230            result = {
3231                options: {  // options structure passed to jQuery Validate's validate() method
3232                    errorClass: "input-validation-error",
3233                    errorElement: "span",
3234                    errorPlacement: $.proxy(onError, form),
3235                    invalidHandler: $.proxy(onErrors, form),
3236                    messages: {},
3237                    rules: {},
3238                    success: $.proxy(onSuccess, form)
3239                },
3240                attachValidation: function () {
3241                    $form
3242                        .unbind("reset." + data_validation, onResetProxy)
3243                        .bind("reset." + data_validation, onResetProxy)
3244                        .validate(this.options);
3245                },
3246                validate: function () {  // a validation function that is called by unobtrusive Ajax
3247                    $form.validate();
3248                    return $form.valid();
3249                }
3250            };
3251            $form.data(data_validation, result);
3252        }
3253
3254        return result;
3255    }
3256
3257    $jQval.unobtrusive = {
3258        adapters: [],
3259
3260        parseElement: function (element, skipAttach) {
3261            /// <summary>
3262            /// Parses a single HTML element for unobtrusive validation attributes.
3263            /// </summary>
3264            /// <param name="element" domElement="true">The HTML element to be parsed.</param>
3265            /// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
3266            /// validation to the form. If parsing just this single element, you should specify true.
3267            /// If parsing several elements, you should specify false, and manually attach the validation
3268            /// to the form when you are finished. The default is false.</param>
3269            var $element = $(element),
3270                form = $element.parents("form")[0],
3271                valInfo, rules, messages;
3272
3273            if (!form) {  // Cannot do client-side validation without a form
3274                return;
3275            }
3276
3277            valInfo = validationInfo(form);
3278            valInfo.options.rules[element.name] = rules = {};
3279            valInfo.options.messages[element.name] = messages = {};
3280
3281            $.each(this.adapters, function () {
3282                var prefix = "data-val-" + this.name,
3283                    message = $element.attr(prefix),
3284                    paramValues = {};
3285
3286                if (message !== undefined) {  // Compare against undefined, because an empty message is legal (and falsy)
3287                    prefix += "-";
3288
3289                    $.each(this.params, function () {
3290                        paramValues[this] = $element.attr(prefix + this);
3291                    });
3292
3293                    this.adapt({
3294                        element: element,
3295                        form: form,
3296                        message: message,
3297                        params: paramValues,
3298                        rules: rules,
3299                        messages: messages
3300                    });
3301                }
3302            });
3303
3304            $.extend(rules, { "__dummy__": true });
3305
3306            if (!skipAttach) {
3307                valInfo.attachValidation();
3308            }
3309        },
3310
3311        parse: function (selector) {
3312            /// <summary>
3313            /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
3314            /// with the [data-val=true] attribute value and enables validation according to the data-val-*
3315            /// attribute values.
3316            /// </summary>
3317            /// <param name="selector" type="String">Any valid jQuery selector.</param>
3318            var $forms = $(selector)
3319                .parents("form")
3320                .andSelf()
3321                .add($(selector).find("form"))
3322                .filter("form");
3323
3324            $(selector).find(":input[data-val=true]").each(function () {
3325                $jQval.unobtrusive.parseElement(this, true);
3326            });
3327
3328            $forms.each(function () {
3329                var info = validationInfo(this);
3330                if (info) {
3331                    info.attachValidation();
3332                }
3333            });
3334        }
3335    };
3336
3337    adapters = $jQval.unobtrusive.adapters;
3338
3339    adapters.add = function (adapterName, params, fn) {
3340        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
3341        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
3342        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
3343        /// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
3344        /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
3345        /// mmmm is the parameter name).</param>
3346        /// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
3347        /// attributes into jQuery Validate rules and/or messages.</param>
3348        /// <returns type="jQuery.validator.unobtrusive.adapters" />
3349        if (!fn) {  // Called with no params, just a function
3350            fn = params;
3351            params = [];
3352        }
3353        this.push({ name: adapterName, params: params, adapt: fn });
3354        return this;
3355    };
3356
3357    adapters.addBool = function (adapterName, ruleName) {
3358        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
3359        /// the jQuery Validate validation rule has no parameter values.</summary>
3360        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
3361        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
3362        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
3363        /// of adapterName will be used instead.</param>
3364        /// <returns type="jQuery.validator.unobtrusive.adapters" />
3365        return this.add(adapterName, function (options) {
3366            setValidationValues(options, ruleName || adapterName, true);
3367        });
3368    };
3369
3370    adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
3371        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
3372        /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
3373        /// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
3374        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
3375        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
3376        /// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
3377        /// have a minimum value.</param>
3378        /// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
3379        /// have a maximum value.</param>
3380        /// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
3381        /// have both a minimum and maximum value.</param>
3382        /// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
3383        /// contains the minimum value. The default is "min".</param>
3384        /// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
3385        /// contains the maximum value. The default is "max".</param>
3386        /// <returns type="jQuery.validator.unobtrusive.adapters" />
3387        return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
3388            var min = options.params.min,
3389                max = options.params.max;
3390
3391            if (min && max) {
3392                setValidationValues(options, minMaxRuleName, [min, max]);
3393            }
3394            else if (min) {
3395                setValidationValues(options, minRuleName, min);
3396            }
3397            else if (max) {
3398                setValidationValues(options, maxRuleName, max);
3399            }
3400        });
3401    };
3402
3403    adapters.addSingleVal = function (adapterName, attribute, ruleName) {
3404        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
3405        /// the jQuery Validate validation rule has a single value.</summary>
3406        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
3407        /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
3408        /// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
3409        /// The default is "val".</param>
3410        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
3411        /// of adapterName will be used instead.</param>
3412        /// <returns type="jQuery.validator.unobtrusive.adapters" />
3413        return this.add(adapterName, [attribute || "val"], function (options) {
3414            setValidationValues(options, ruleName || adapterName, options.params[attribute]);
3415        });
3416    };
3417
3418    $jQval.addMethod("__dummy__", function (value, element, params) {
3419        return true;
3420    });
3421
3422    $jQval.addMethod("regex", function (value, element, params) {
3423        var match;
3424        if (this.optional(element)) {
3425            return true;
3426        }
3427
3428        match = new RegExp(params).exec(value);
3429        return (match && (match.index === 0) && (match[0].length === value.length));
3430    });
3431
3432    $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
3433        var match;
3434        if (nonalphamin) {
3435            match = value.match(/\W/g);
3436            match = match && match.length >= nonalphamin;
3437        }
3438        return match;
3439    });
3440
3441    adapters.addSingleVal("accept", "exts").addSingleVal("regex", "pattern");
3442    adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
3443    adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
3444    adapters.add("equalto", ["other"], function (options) {
3445        var prefix = getModelPrefix(options.element.name),
3446            other = options.params.other,
3447            fullOtherName = appendModelPrefix(other, prefix),
3448            element = $(options.form).find(":input[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
3449
3450        setValidationValues(options, "equalTo", element);
3451    });
3452    adapters.add("required", function (options) {
3453        // jQuery Validate equates "required" with "mandatory" for checkbox elements
3454        if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
3455            setValidationValues(options, "required", true);
3456        }
3457    });
3458    adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
3459        var value = {
3460            url: options.params.url,
3461            type: options.params.type || "GET",
3462            data: {}
3463        },
3464            prefix = getModelPrefix(options.element.name);
3465
3466        $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
3467            var paramName = appendModelPrefix(fieldName, prefix);
3468            value.data[paramName] = function () {
3469                return $(options.form).find(":input[name='" + escapeAttributeValue(paramName) + "']").val();
3470            };
3471        });
3472
3473        setValidationValues(options, "remote", value);
3474    });
3475    adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
3476        if (options.params.min) {
3477            setValidationValues(options, "minlength", options.params.min);
3478        }
3479        if (options.params.nonalphamin) {
3480            setValidationValues(options, "nonalphamin", options.params.nonalphamin);
3481        }
3482        if (options.params.regex) {
3483            setValidationValues(options, "regex", options.params.regex);
3484        }
3485    });
3486
3487    $(function () {
3488        $jQval.unobtrusive.parse(document);
3489    });
3490} (jQuery));
3491//     Underscore.js 1.8.3
3492//     http://underscorejs.org
3493//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
3494//     Underscore may be freely distributed under the MIT license.
3495
3496(function() {
3497
3498  // Baseline setup
3499  // --------------
3500
3501  // Establish the root object, `window` in the browser, or `exports` on the server.
3502  var root = this;
3503
3504  // Save the previous value of the `_` variable.
3505  var previousUnderscore = root._;
3506
3507  // Save bytes in the minified (but not gzipped) version:
3508  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
3509
3510  // Create quick reference variables for speed access to core prototypes.
3511  var
3512    push             = ArrayProto.push,
3513    slice            = ArrayProto.slice,
3514    toString         = ObjProto.toString,
3515    hasOwnProperty   = ObjProto.hasOwnProperty;
3516
3517  // All **ECMAScript 5** native function implementations that we hope to use
3518  // are declared here.
3519  var
3520    nativeIsArray      = Array.isArray,
3521    nativeKeys         = Object.keys,
3522    nativeBind         = FuncProto.bind,
3523    nativeCreate       = Object.create;
3524
3525  // Naked function reference for surrogate-prototype-swapping.
3526  var Ctor = function(){};
3527
3528  // Create a safe reference to the Underscore object for use below.
3529  var _ = function(obj) {
3530    if (obj instanceof _) return obj;
vendor: 53,040 bytes, lines 3531-5036
3531    if (!(this instanceof _)) return new _(obj);
3532    this._wrapped = obj;
3533  };
3534
3535  // Export the Underscore object for **Node.js**, with
3536  // backwards-compatibility for the old `require()` API. If we're in
3537  // the browser, add `_` as a global object.
3538  if (typeof exports !== 'undefined') {
3539    if (typeof module !== 'undefined' && module.exports) {
3540      exports = module.exports = _;
3541    }
3542    exports._ = _;
3543  } else {
3544    root._ = _;
3545  }
3546
3547  // Current version.
3548  _.VERSION = '1.8.3';
3549
3550  // Internal function that returns an efficient (for current engines) version
3551  // of the passed-in callback, to be repeatedly applied in other Underscore
3552  // functions.
3553  var optimizeCb = function(func, context, argCount) {
3554    if (context === void 0) return func;
3555    switch (argCount == null ? 3 : argCount) {
3556      case 1: return function(value) {
3557        return func.call(context, value);
3558      };
3559      case 2: return function(value, other) {
3560        return func.call(context, value, other);
3561      };
3562      case 3: return function(value, index, collection) {
3563        return func.call(context, value, index, collection);
3564      };
3565      case 4: return function(accumulator, value, index, collection) {
3566        return func.call(context, accumulator, value, index, collection);
3567      };
3568    }
3569    return function() {
3570      return func.apply(context, arguments);
3571    };
3572  };
3573
3574  // A mostly-internal function to generate callbacks that can be applied
3575  // to each element in a collection, returning the desired result — either
3576  // identity, an arbitrary callback, a property matcher, or a property accessor.
3577  var cb = function(value, context, argCount) {
3578    if (value == null) return _.identity;
3579    if (_.isFunction(value)) return optimizeCb(value, context, argCount);
3580    if (_.isObject(value)) return _.matcher(value);
3581    return _.property(value);
3582  };
3583  _.iteratee = function(value, context) {
3584    return cb(value, context, Infinity);
3585  };
3586
3587  // An internal function for creating assigner functions.
3588  var createAssigner = function(keysFunc, undefinedOnly) {
3589    return function(obj) {
3590      var length = arguments.length;
3591      if (length < 2 || obj == null) return obj;
3592      for (var index = 1; index < length; index++) {
3593        var source = arguments[index],
3594            keys = keysFunc(source),
3595            l = keys.length;
3596        for (var i = 0; i < l; i++) {
3597          var key = keys[i];
3598          if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
3599        }
3600      }
3601      return obj;
3602    };
3603  };
3604
3605  // An internal function for creating a new object that inherits from another.
3606  var baseCreate = function(prototype) {
3607    if (!_.isObject(prototype)) return {};
3608    if (nativeCreate) return nativeCreate(prototype);
3609    Ctor.prototype = prototype;
3610    var result = new Ctor;
3611    Ctor.prototype = null;
3612    return result;
3613  };
3614
3615  var property = function(key) {
3616    return function(obj) {
3617      return obj == null ? void 0 : obj[key];
3618    };
3619  };
3620
3621  // Helper for collection methods to determine whether a collection
3622  // should be iterated as an array or as an object
3623  // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
3624  // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
3625  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
3626  var getLength = property('length');
3627  var isArrayLike = function(collection) {
3628    var length = getLength(collection);
3629    return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
3630  };
3631
3632  // Collection Functions
3633  // --------------------
3634
3635  // The cornerstone, an `each` implementation, aka `forEach`.
3636  // Handles raw objects in addition to array-likes. Treats all
3637  // sparse array-likes as if they were dense.
3638  _.each = _.forEach = function(obj, iteratee, context) {
3639    iteratee = optimizeCb(iteratee, context);
3640    var i, length;
3641    if (isArrayLike(obj)) {
3642      for (i = 0, length = obj.length; i < length; i++) {
3643        iteratee(obj[i], i, obj);
3644      }
3645    } else {
3646      var keys = _.keys(obj);
3647      for (i = 0, length = keys.length; i < length; i++) {
3648        iteratee(obj[keys[i]], keys[i], obj);
3649      }
3650    }
3651    return obj;
3652  };
3653
3654  // Return the results of applying the iteratee to each element.
3655  _.map = _.collect = function(obj, iteratee, context) {
3656    iteratee = cb(iteratee, context);
3657    var keys = !isArrayLike(obj) && _.keys(obj),
3658        length = (keys || obj).length,
3659        results = Array(length);
3660    for (var index = 0; index < length; index++) {
3661      var currentKey = keys ? keys[index] : index;
3662      results[index] = iteratee(obj[currentKey], currentKey, obj);
3663    }
3664    return results;
3665  };
3666
3667  // Create a reducing function iterating left or right.
3668  function createReduce(dir) {
3669    // Optimized iterator function as using arguments.length
3670    // in the main function will deoptimize the, see #1991.
3671    function iterator(obj, iteratee, memo, keys, index, length) {
3672      for (; index >= 0 && index < length; index += dir) {
3673        var currentKey = keys ? keys[index] : index;
3674        memo = iteratee(memo, obj[currentKey], currentKey, obj);
3675      }
3676      return memo;
3677    }
3678
3679    return function(obj, iteratee, memo, context) {
3680      iteratee = optimizeCb(iteratee, context, 4);
3681      var keys = !isArrayLike(obj) && _.keys(obj),
3682          length = (keys || obj).length,
3683          index = dir > 0 ? 0 : length - 1;
3684      // Determine the initial value if none is provided.
3685      if (arguments.length < 3) {
3686        memo = obj[keys ? keys[index] : index];
3687        index += dir;
3688      }
3689      return iterator(obj, iteratee, memo, keys, index, length);
3690    };
3691  }
3692
3693  // **Reduce** builds up a single result from a list of values, aka `inject`,
3694  // or `foldl`.
3695  _.reduce = _.foldl = _.inject = createReduce(1);
3696
3697  // The right-associative version of reduce, also known as `foldr`.
3698  _.reduceRight = _.foldr = createReduce(-1);
3699
3700  // Return the first value which passes a truth test. Aliased as `detect`.
3701  _.find = _.detect = function(obj, predicate, context) {
3702    var key;
3703    if (isArrayLike(obj)) {
3704      key = _.findIndex(obj, predicate, context);
3705    } else {
3706      key = _.findKey(obj, predicate, context);
3707    }
3708    if (key !== void 0 && key !== -1) return obj[key];
3709  };
3710
3711  // Return all the elements that pass a truth test.
3712  // Aliased as `select`.
3713  _.filter = _.select = function(obj, predicate, context) {
3714    var results = [];
3715    predicate = cb(predicate, context);
3716    _.each(obj, function(value, index, list) {
3717      if (predicate(value, index, list)) results.push(value);
3718    });
3719    return results;
3720  };
3721
3722  // Return all the elements for which a truth test fails.
3723  _.reject = function(obj, predicate, context) {
3724    return _.filter(obj, _.negate(cb(predicate)), context);
3725  };
3726
3727  // Determine whether all of the elements match a truth test.
3728  // Aliased as `all`.
3729  _.every = _.all = function(obj, predicate, context) {
3730    predicate = cb(predicate, context);
3731    var keys = !isArrayLike(obj) && _.keys(obj),
3732        length = (keys || obj).length;
3733    for (var index = 0; index < length; index++) {
3734      var currentKey = keys ? keys[index] : index;
3735      if (!predicate(obj[currentKey], currentKey, obj)) return false;
3736    }
3737    return true;
3738  };
3739
3740  // Determine if at least one element in the object matches a truth test.
3741  // Aliased as `any`.
3742  _.some = _.any = function(obj, predicate, context) {
3743    predicate = cb(predicate, context);
3744    var keys = !isArrayLike(obj) && _.keys(obj),
3745        length = (keys || obj).length;
3746    for (var index = 0; index < length; index++) {
3747      var currentKey = keys ? keys[index] : index;
3748      if (predicate(obj[currentKey], currentKey, obj)) return true;
3749    }
3750    return false;
3751  };
3752
3753  // Determine if the array or object contains a given item (using `===`).
3754  // Aliased as `includes` and `include`.
3755  _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
3756    if (!isArrayLike(obj)) obj = _.values(obj);
3757    if (typeof fromIndex != 'number' || guard) fromIndex = 0;
3758    return _.indexOf(obj, item, fromIndex) >= 0;
3759  };
3760
3761  // Invoke a method (with arguments) on every item in a collection.
3762  _.invoke = function(obj, method) {
3763    var args = slice.call(arguments, 2);
3764    var isFunc = _.isFunction(method);
3765    return _.map(obj, function(value) {
3766      var func = isFunc ? method : value[method];
3767      return func == null ? func : func.apply(value, args);
3768    });
3769  };
3770
3771  // Convenience version of a common use case of `map`: fetching a property.
3772  _.pluck = function(obj, key) {
3773    return _.map(obj, _.property(key));
3774  };
3775
3776  // Convenience version of a common use case of `filter`: selecting only objects
3777  // containing specific `key:value` pairs.
3778  _.where = function(obj, attrs) {
3779    return _.filter(obj, _.matcher(attrs));
3780  };
3781
3782  // Convenience version of a common use case of `find`: getting the first object
3783  // containing specific `key:value` pairs.
3784  _.findWhere = function(obj, attrs) {
3785    return _.find(obj, _.matcher(attrs));
3786  };
3787
3788  // Return the maximum element (or element-based computation).
3789  _.max = function(obj, iteratee, context) {
3790    var result = -Infinity, lastComputed = -Infinity,
3791        value, computed;
3792    if (iteratee == null && obj != null) {
3793      obj = isArrayLike(obj) ? obj : _.values(obj);
3794      for (var i = 0, length = obj.length; i < length; i++) {
3795        value = obj[i];
3796        if (value > result) {
3797          result = value;
3798        }
3799      }
3800    } else {
3801      iteratee = cb(iteratee, context);
3802      _.each(obj, function(value, index, list) {
3803        computed = iteratee(value, index, list);
3804        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
3805          result = value;
3806          lastComputed = computed;
3807        }
3808      });
3809    }
3810    return result;
3811  };
3812
3813  // Return the minimum element (or element-based computation).
3814  _.min = function(obj, iteratee, context) {
3815    var result = Infinity, lastComputed = Infinity,
3816        value, computed;
3817    if (iteratee == null && obj != null) {
3818      obj = isArrayLike(obj) ? obj : _.values(obj);
3819      for (var i = 0, length = obj.length; i < length; i++) {
3820        value = obj[i];
3821        if (value < result) {
3822          result = value;
3823        }
3824      }
3825    } else {
3826      iteratee = cb(iteratee, context);
3827      _.each(obj, function(value, index, list) {
3828        computed = iteratee(value, index, list);
3829        if (computed < lastComputed || computed === Infinity && result === Infinity) {
3830          result = value;
3831          lastComputed = computed;
3832        }
3833      });
3834    }
3835    return result;
3836  };
3837
3838  // Shuffle a collection, using the modern version of the
3839  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
3840  _.shuffle = function(obj) {
3841    var set = isArrayLike(obj) ? obj : _.values(obj);
3842    var length = set.length;
3843    var shuffled = Array(length);
3844    for (var index = 0, rand; index < length; index++) {
3845      rand = _.random(0, index);
3846      if (rand !== index) shuffled[index] = shuffled[rand];
3847      shuffled[rand] = set[index];
3848    }
3849    return shuffled;
3850  };
3851
3852  // Sample **n** random values from a collection.
3853  // If **n** is not specified, returns a single random element.
3854  // The internal `guard` argument allows it to work with `map`.
3855  _.sample = function(obj, n, guard) {
3856    if (n == null || guard) {
3857      if (!isArrayLike(obj)) obj = _.values(obj);
3858      return obj[_.random(obj.length - 1)];
3859    }
3860    return _.shuffle(obj).slice(0, Math.max(0, n));
3861  };
3862
3863  // Sort the object's values by a criterion produced by an iteratee.
3864  _.sortBy = function(obj, iteratee, context) {
3865    iteratee = cb(iteratee, context);
3866    return _.pluck(_.map(obj, function(value, index, list) {
3867      return {
3868        value: value,
3869        index: index,
3870        criteria: iteratee(value, index, list)
3871      };
3872    }).sort(function(left, right) {
3873      var a = left.criteria;
3874      var b = right.criteria;
3875      if (a !== b) {
3876        if (a > b || a === void 0) return 1;
3877        if (a < b || b === void 0) return -1;
3878      }
3879      return left.index - right.index;
3880    }), 'value');
3881  };
3882
3883  // An internal function used for aggregate "group by" operations.
3884  var group = function(behavior) {
3885    return function(obj, iteratee, context) {
3886      var result = {};
3887      iteratee = cb(iteratee, context);
3888      _.each(obj, function(value, index) {
3889        var key = iteratee(value, index, obj);
3890        behavior(result, value, key);
3891      });
3892      return result;
3893    };
3894  };
3895
3896  // Groups the object's values by a criterion. Pass either a string attribute
3897  // to group by, or a function that returns the criterion.
3898  _.groupBy = group(function(result, value, key) {
3899    if (_.has(result, key)) result[key].push(value); else result[key] = [value];
3900  });
3901
3902  // Indexes the object's values by a criterion, similar to `groupBy`, but for
3903  // when you know that your index values will be unique.
3904  _.indexBy = group(function(result, value, key) {
3905    result[key] = value;
3906  });
3907
3908  // Counts instances of an object that group by a certain criterion. Pass
3909  // either a string attribute to count by, or a function that returns the
3910  // criterion.
3911  _.countBy = group(function(result, value, key) {
3912    if (_.has(result, key)) result[key]++; else result[key] = 1;
3913  });
3914
3915  // Safely create a real, live array from anything iterable.
3916  _.toArray = function(obj) {
3917    if (!obj) return [];
3918    if (_.isArray(obj)) return slice.call(obj);
3919    if (isArrayLike(obj)) return _.map(obj, _.identity);
3920    return _.values(obj);
3921  };
3922
3923  // Return the number of elements in an object.
3924  _.size = function(obj) {
3925    if (obj == null) return 0;
3926    return isArrayLike(obj) ? obj.length : _.keys(obj).length;
3927  };
3928
3929  // Split a collection into two arrays: one whose elements all satisfy the given
3930  // predicate, and one whose elements all do not satisfy the predicate.
3931  _.partition = function(obj, predicate, context) {
3932    predicate = cb(predicate, context);
3933    var pass = [], fail = [];
3934    _.each(obj, function(value, key, obj) {
3935      (predicate(value, key, obj) ? pass : fail).push(value);
3936    });
3937    return [pass, fail];
3938  };
3939
3940  // Array Functions
3941  // ---------------
3942
3943  // Get the first element of an array. Passing **n** will return the first N
3944  // values in the array. Aliased as `head` and `take`. The **guard** check
3945  // allows it to work with `_.map`.
3946  _.first = _.head = _.take = function(array, n, guard) {
3947    if (array == null) return void 0;
3948    if (n == null || guard) return array[0];
3949    return _.initial(array, array.length - n);
3950  };
3951
3952  // Returns everything but the last entry of the array. Especially useful on
3953  // the arguments object. Passing **n** will return all the values in
3954  // the array, excluding the last N.
3955  _.initial = function(array, n, guard) {
3956    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
3957  };
3958
3959  // Get the last element of an array. Passing **n** will return the last N
3960  // values in the array.
3961  _.last = function(array, n, guard) {
3962    if (array == null) return void 0;
3963    if (n == null || guard) return array[array.length - 1];
3964    return _.rest(array, Math.max(0, array.length - n));
3965  };
3966
3967  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
3968  // Especially useful on the arguments object. Passing an **n** will return
3969  // the rest N values in the array.
3970  _.rest = _.tail = _.drop = function(array, n, guard) {
3971    return slice.call(array, n == null || guard ? 1 : n);
3972  };
3973
3974  // Trim out all falsy values from an array.
3975  _.compact = function(array) {
3976    return _.filter(array, _.identity);
3977  };
3978
3979  // Internal implementation of a recursive `flatten` function.
3980  var flatten = function(input, shallow, strict, startIndex) {
3981    var output = [], idx = 0;
3982    for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
3983      var value = input[i];
3984      if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
3985        //flatten current level of array or arguments object
3986        if (!shallow) value = flatten(value, shallow, strict);
3987        var j = 0, len = value.length;
3988        output.length += len;
3989        while (j < len) {
3990          output[idx++] = value[j++];
3991        }
3992      } else if (!strict) {
3993        output[idx++] = value;
3994      }
3995    }
3996    return output;
3997  };
3998
3999  // Flatten out an array, either recursively (by default), or just one level.
4000  _.flatten = function(array, shallow) {
4001    return flatten(array, shallow, false);
4002  };
4003
4004  // Return a version of the array that does not contain the specified value(s).
4005  _.without = function(array) {
4006    return _.difference(array, slice.call(arguments, 1));
4007  };
4008
4009  // Produce a duplicate-free version of the array. If the array has already
4010  // been sorted, you have the option of using a faster algorithm.
4011  // Aliased as `unique`.
4012  _.uniq = _.unique = function(array, isSorted, iteratee, context) {
4013    if (!_.isBoolean(isSorted)) {
4014      context = iteratee;
4015      iteratee = isSorted;
4016      isSorted = false;
4017    }
4018    if (iteratee != null) iteratee = cb(iteratee, context);
4019    var result = [];
4020    var seen = [];
4021    for (var i = 0, length = getLength(array); i < length; i++) {
4022      var value = array[i],
4023          computed = iteratee ? iteratee(value, i, array) : value;
4024      if (isSorted) {
4025        if (!i || seen !== computed) result.push(value);
4026        seen = computed;
4027      } else if (iteratee) {
4028        if (!_.contains(seen, computed)) {
4029          seen.push(computed);
4030          result.push(value);
4031        }
4032      } else if (!_.contains(result, value)) {
4033        result.push(value);
4034      }
4035    }
4036    return result;
4037  };
4038
4039  // Produce an array that contains the union: each distinct element from all of
4040  // the passed-in arrays.
4041  _.union = function() {
4042    return _.uniq(flatten(arguments, true, true));
4043  };
4044
4045  // Produce an array that contains every item shared between all the
4046  // passed-in arrays.
4047  _.intersection = function(array) {
4048    var result = [];
4049    var argsLength = arguments.length;
4050    for (var i = 0, length = getLength(array); i < length; i++) {
4051      var item = array[i];
4052      if (_.contains(result, item)) continue;
4053      for (var j = 1; j < argsLength; j++) {
4054        if (!_.contains(arguments[j], item)) break;
4055      }
4056      if (j === argsLength) result.push(item);
4057    }
4058    return result;
4059  };
4060
4061  // Take the difference between one array and a number of other arrays.
4062  // Only the elements present in just the first array will remain.
4063  _.difference = function(array) {
4064    var rest = flatten(arguments, true, true, 1);
4065    return _.filter(array, function(value){
4066      return !_.contains(rest, value);
4067    });
4068  };
4069
4070  // Zip together multiple lists into a single array -- elements that share
4071  // an index go together.
4072  _.zip = function() {
4073    return _.unzip(arguments);
4074  };
4075
4076  // Complement of _.zip. Unzip accepts an array of arrays and groups
4077  // each array's elements on shared indices
4078  _.unzip = function(array) {
4079    var length = array && _.max(array, getLength).length || 0;
4080    var result = Array(length);
4081
4082    for (var index = 0; index < length; index++) {
4083      result[index] = _.pluck(array, index);
4084    }
4085    return result;
4086  };
4087
4088  // Converts lists into objects. Pass either a single array of `[key, value]`
4089  // pairs, or two parallel arrays of the same length -- one of keys, and one of
4090  // the corresponding values.
4091  _.object = function(list, values) {
4092    var result = {};
4093    for (var i = 0, length = getLength(list); i < length; i++) {
4094      if (values) {
4095        result[list[i]] = values[i];
4096      } else {
4097        result[list[i][0]] = list[i][1];
4098      }
4099    }
4100    return result;
4101  };
4102
4103  // Generator function to create the findIndex and findLastIndex functions
4104  function createPredicateIndexFinder(dir) {
4105    return function(array, predicate, context) {
4106      predicate = cb(predicate, context);
4107      var length = getLength(array);
4108      var index = dir > 0 ? 0 : length - 1;
4109      for (; index >= 0 && index < length; index += dir) {
4110        if (predicate(array[index], index, array)) return index;
4111      }
4112      return -1;
4113    };
4114  }
4115
4116  // Returns the first index on an array-like that passes a predicate test
4117  _.findIndex = createPredicateIndexFinder(1);
4118  _.findLastIndex = createPredicateIndexFinder(-1);
4119
4120  // Use a comparator function to figure out the smallest index at which
4121  // an object should be inserted so as to maintain order. Uses binary search.
4122  _.sortedIndex = function(array, obj, iteratee, context) {
4123    iteratee = cb(iteratee, context, 1);
4124    var value = iteratee(obj);
4125    var low = 0, high = getLength(array);
4126    while (low < high) {
4127      var mid = Math.floor((low + high) / 2);
4128      if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
4129    }
4130    return low;
4131  };
4132
4133  // Generator function to create the indexOf and lastIndexOf functions
4134  function createIndexFinder(dir, predicateFind, sortedIndex) {
4135    return function(array, item, idx) {
4136      var i = 0, length = getLength(array);
4137      if (typeof idx == 'number') {
4138        if (dir > 0) {
4139            i = idx >= 0 ? idx : Math.max(idx + length, i);
4140        } else {
4141            length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
4142        }
4143      } else if (sortedIndex && idx && length) {
4144        idx = sortedIndex(array, item);
4145        return array[idx] === item ? idx : -1;
4146      }
4147      if (item !== item) {
4148        idx = predicateFind(slice.call(array, i, length), _.isNaN);
4149        return idx >= 0 ? idx + i : -1;
4150      }
4151      for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
4152        if (array[idx] === item) return idx;
4153      }
4154      return -1;
4155    };
4156  }
4157
4158  // Return the position of the first occurrence of an item in an array,
4159  // or -1 if the item is not included in the array.
4160  // If the array is large and already in sort order, pass `true`
4161  // for **isSorted** to use binary search.
4162  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
4163  _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
4164
4165  // Generate an integer Array containing an arithmetic progression. A port of
4166  // the native Python `range()` function. See
4167  // [the Python documentation](http://docs.python.org/library/functions.html#range).
4168  _.range = function(start, stop, step) {
4169    if (stop == null) {
4170      stop = start || 0;
4171      start = 0;
4172    }
4173    step = step || 1;
4174
4175    var length = Math.max(Math.ceil((stop - start) / step), 0);
4176    var range = Array(length);
4177
4178    for (var idx = 0; idx < length; idx++, start += step) {
4179      range[idx] = start;
4180    }
4181
4182    return range;
4183  };
4184
4185  // Function (ahem) Functions
4186  // ------------------
4187
4188  // Determines whether to execute a function as a constructor
4189  // or a normal function with the provided arguments
4190  var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
4191    if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
4192    var self = baseCreate(sourceFunc.prototype);
4193    var result = sourceFunc.apply(self, args);
4194    if (_.isObject(result)) return result;
4195    return self;
4196  };
4197
4198  // Create a function bound to a given object (assigning `this`, and arguments,
4199  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
4200  // available.
4201  _.bind = function(func, context) {
4202    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
4203    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
4204    var args = slice.call(arguments, 2);
4205    var bound = function() {
4206      return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
4207    };
4208    return bound;
4209  };
4210
4211  // Partially apply a function by creating a version that has had some of its
4212  // arguments pre-filled, without changing its dynamic `this` context. _ acts
4213  // as a placeholder, allowing any combination of arguments to be pre-filled.
4214  _.partial = function(func) {
4215    var boundArgs = slice.call(arguments, 1);
4216    var bound = function() {
4217      var position = 0, length = boundArgs.length;
4218      var args = Array(length);
4219      for (var i = 0; i < length; i++) {
4220        args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
4221      }
4222      while (position < arguments.length) args.push(arguments[position++]);
4223      return executeBound(func, bound, this, this, args);
4224    };
4225    return bound;
4226  };
4227
4228  // Bind a number of an object's methods to that object. Remaining arguments
4229  // are the method names to be bound. Useful for ensuring that all callbacks
4230  // defined on an object belong to it.
4231  _.bindAll = function(obj) {
4232    var i, length = arguments.length, key;
4233    if (length <= 1) throw new Error('bindAll must be passed function names');
4234    for (i = 1; i < length; i++) {
4235      key = arguments[i];
4236      obj[key] = _.bind(obj[key], obj);
4237    }
4238    return obj;
4239  };
4240
4241  // Memoize an expensive function by storing its results.
4242  _.memoize = function(func, hasher) {
4243    var memoize = function(key) {
4244      var cache = memoize.cache;
4245      var address = '' + (hasher ? hasher.apply(this, arguments) : key);
4246      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
4247      return cache[address];
4248    };
4249    memoize.cache = {};
4250    return memoize;
4251  };
4252
4253  // Delays a function for the given number of milliseconds, and then calls
4254  // it with the arguments supplied.
4255  _.delay = function(func, wait) {
4256    var args = slice.call(arguments, 2);
4257    return setTimeout(function(){
4258      return func.apply(null, args);
4259    }, wait);
4260  };
4261
4262  // Defers a function, scheduling it to run after the current call stack has
4263  // cleared.
4264  _.defer = _.partial(_.delay, _, 1);
4265
4266  // Returns a function, that, when invoked, will only be triggered at most once
4267  // during a given window of time. Normally, the throttled function will run
4268  // as much as it can, without ever going more than once per `wait` duration;
4269  // but if you'd like to disable the execution on the leading edge, pass
4270  // `{leading: false}`. To disable execution on the trailing edge, ditto.
4271  _.throttle = function(func, wait, options) {
4272    var context, args, result;
4273    var timeout = null;
4274    var previous = 0;
4275    if (!options) options = {};
4276    var later = function() {
4277      previous = options.leading === false ? 0 : _.now();
4278      timeout = null;
4279      result = func.apply(context, args);
4280      if (!timeout) context = args = null;
4281    };
4282    return function() {
4283      var now = _.now();
4284      if (!previous && options.leading === false) previous = now;
4285      var remaining = wait - (now - previous);
4286      context = this;
4287      args = arguments;
4288      if (remaining <= 0 || remaining > wait) {
4289        if (timeout) {
4290          clearTimeout(timeout);
4291          timeout = null;
4292        }
4293        previous = now;
4294        result = func.apply(context, args);
4295        if (!timeout) context = args = null;
4296      } else if (!timeout && options.trailing !== false) {
4297        timeout = setTimeout(later, remaining);
4298      }
4299      return result;
4300    };
4301  };
4302
4303  // Returns a function, that, as long as it continues to be invoked, will not
4304  // be triggered. The function will be called after it stops being called for
4305  // N milliseconds. If `immediate` is passed, trigger the function on the
4306  // leading edge, instead of the trailing.
4307  _.debounce = function(func, wait, immediate) {
4308    var timeout, args, context, timestamp, result;
4309
4310    var later = function() {
4311      var last = _.now() - timestamp;
4312
4313      if (last < wait && last >= 0) {
4314        timeout = setTimeout(later, wait - last);
4315      } else {
4316        timeout = null;
4317        if (!immediate) {
4318          result = func.apply(context, args);
4319          if (!timeout) context = args = null;
4320        }
4321      }
4322    };
4323
4324    return function() {
4325      context = this;
4326      args = arguments;
4327      timestamp = _.now();
4328      var callNow = immediate && !timeout;
4329      if (!timeout) timeout = setTimeout(later, wait);
4330      if (callNow) {
4331        result = func.apply(context, args);
4332        context = args = null;
4333      }
4334
4335      return result;
4336    };
4337  };
4338
4339  // Returns the first function passed as an argument to the second,
4340  // allowing you to adjust arguments, run code before and after, and
4341  // conditionally execute the original function.
4342  _.wrap = function(func, wrapper) {
4343    return _.partial(wrapper, func);
4344  };
4345
4346  // Returns a negated version of the passed-in predicate.
4347  _.negate = function(predicate) {
4348    return function() {
4349      return !predicate.apply(this, arguments);
4350    };
4351  };
4352
4353  // Returns a function that is the composition of a list of functions, each
4354  // consuming the return value of the function that follows.
4355  _.compose = function() {
4356    var args = arguments;
4357    var start = args.length - 1;
4358    return function() {
4359      var i = start;
4360      var result = args[start].apply(this, arguments);
4361      while (i--) result = args[i].call(this, result);
4362      return result;
4363    };
4364  };
4365
4366  // Returns a function that will only be executed on and after the Nth call.
4367  _.after = function(times, func) {
4368    return function() {
4369      if (--times < 1) {
4370        return func.apply(this, arguments);
4371      }
4372    };
4373  };
4374
4375  // Returns a function that will only be executed up to (but not including) the Nth call.
4376  _.before = function(times, func) {
4377    var memo;
4378    return function() {
4379      if (--times > 0) {
4380        memo = func.apply(this, arguments);
4381      }
4382      if (times <= 1) func = null;
4383      return memo;
4384    };
4385  };
4386
4387  // Returns a function that will be executed at most one time, no matter how
4388  // often you call it. Useful for lazy initialization.
4389  _.once = _.partial(_.before, 2);
4390
4391  // Object Functions
4392  // ----------------
4393
4394  // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
4395  var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
4396  var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
4397                      'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
4398
4399  function collectNonEnumProps(obj, keys) {
4400    var nonEnumIdx = nonEnumerableProps.length;
4401    var constructor = obj.constructor;
4402    var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
4403
4404    // Constructor is a special case.
4405    var prop = 'constructor';
4406    if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
4407
4408    while (nonEnumIdx--) {
4409      prop = nonEnumerableProps[nonEnumIdx];
4410      if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
4411        keys.push(prop);
4412      }
4413    }
4414  }
4415
4416  // Retrieve the names of an object's own properties.
4417  // Delegates to **ECMAScript 5**'s native `Object.keys`
4418  _.keys = function(obj) {
4419    if (!_.isObject(obj)) return [];
4420    if (nativeKeys) return nativeKeys(obj);
4421    var keys = [];
4422    for (var key in obj) if (_.has(obj, key)) keys.push(key);
4423    // Ahem, IE < 9.
4424    if (hasEnumBug) collectNonEnumProps(obj, keys);
4425    return keys;
4426  };
4427
4428  // Retrieve all the property names of an object.
4429  _.allKeys = function(obj) {
4430    if (!_.isObject(obj)) return [];
4431    var keys = [];
4432    for (var key in obj) keys.push(key);
4433    // Ahem, IE < 9.
4434    if (hasEnumBug) collectNonEnumProps(obj, keys);
4435    return keys;
4436  };
4437
4438  // Retrieve the values of an object's properties.
4439  _.values = function(obj) {
4440    var keys = _.keys(obj);
4441    var length = keys.length;
4442    var values = Array(length);
4443    for (var i = 0; i < length; i++) {
4444      values[i] = obj[keys[i]];
4445    }
4446    return values;
4447  };
4448
4449  // Returns the results of applying the iteratee to each element of the object
4450  // In contrast to _.map it returns an object
4451  _.mapObject = function(obj, iteratee, context) {
4452    iteratee = cb(iteratee, context);
4453    var keys =  _.keys(obj),
4454          length = keys.length,
4455          results = {},
4456          currentKey;
4457      for (var index = 0; index < length; index++) {
4458        currentKey = keys[index];
4459        results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
4460      }
4461      return results;
4462  };
4463
4464  // Convert an object into a list of `[key, value]` pairs.
4465  _.pairs = function(obj) {
4466    var keys = _.keys(obj);
4467    var length = keys.length;
4468    var pairs = Array(length);
4469    for (var i = 0; i < length; i++) {
4470      pairs[i] = [keys[i], obj[keys[i]]];
4471    }
4472    return pairs;
4473  };
4474
4475  // Invert the keys and values of an object. The values must be serializable.
4476  _.invert = function(obj) {
4477    var result = {};
4478    var keys = _.keys(obj);
4479    for (var i = 0, length = keys.length; i < length; i++) {
4480      result[obj[keys[i]]] = keys[i];
4481    }
4482    return result;
4483  };
4484
4485  // Return a sorted list of the function names available on the object.
4486  // Aliased as `methods`
4487  _.functions = _.methods = function(obj) {
4488    var names = [];
4489    for (var key in obj) {
4490      if (_.isFunction(obj[key])) names.push(key);
4491    }
4492    return names.sort();
4493  };
4494
4495  // Extend a given object with all the properties in passed-in object(s).
4496  _.extend = createAssigner(_.allKeys);
4497
4498  // Assigns a given object with all the own properties in the passed-in object(s)
4499  // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
4500  _.extendOwn = _.assign = createAssigner(_.keys);
4501
4502  // Returns the first key on an object that passes a predicate test
4503  _.findKey = function(obj, predicate, context) {
4504    predicate = cb(predicate, context);
4505    var keys = _.keys(obj), key;
4506    for (var i = 0, length = keys.length; i < length; i++) {
4507      key = keys[i];
4508      if (predicate(obj[key], key, obj)) return key;
4509    }
4510  };
4511
4512  // Return a copy of the object only containing the whitelisted properties.
4513  _.pick = function(object, oiteratee, context) {
4514    var result = {}, obj = object, iteratee, keys;
4515    if (obj == null) return result;
4516    if (_.isFunction(oiteratee)) {
4517      keys = _.allKeys(obj);
4518      iteratee = optimizeCb(oiteratee, context);
4519    } else {
4520      keys = flatten(arguments, false, false, 1);
4521      iteratee = function(value, key, obj) { return key in obj; };
4522      obj = Object(obj);
4523    }
4524    for (var i = 0, length = keys.length; i < length; i++) {
4525      var key = keys[i];
4526      var value = obj[key];
4527      if (iteratee(value, key, obj)) result[key] = value;
4528    }
4529    return result;
4530  };
4531
4532   // Return a copy of the object without the blacklisted properties.
4533  _.omit = function(obj, iteratee, context) {
4534    if (_.isFunction(iteratee)) {
4535      iteratee = _.negate(iteratee);
4536    } else {
4537      var keys = _.map(flatten(arguments, false, false, 1), String);
4538      iteratee = function(value, key) {
4539        return !_.contains(keys, key);
4540      };
4541    }
4542    return _.pick(obj, iteratee, context);
4543  };
4544
4545  // Fill in a given object with default properties.
4546  _.defaults = createAssigner(_.allKeys, true);
4547
4548  // Creates an object that inherits from the given prototype object.
4549  // If additional properties are provided then they will be added to the
4550  // created object.
4551  _.create = function(prototype, props) {
4552    var result = baseCreate(prototype);
4553    if (props) _.extendOwn(result, props);
4554    return result;
4555  };
4556
4557  // Create a (shallow-cloned) duplicate of an object.
4558  _.clone = function(obj) {
4559    if (!_.isObject(obj)) return obj;
4560    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
4561  };
4562
4563  // Invokes interceptor with the obj, and then returns obj.
4564  // The primary purpose of this method is to "tap into" a method chain, in
4565  // order to perform operations on intermediate results within the chain.
4566  _.tap = function(obj, interceptor) {
4567    interceptor(obj);
4568    return obj;
4569  };
4570
4571  // Returns whether an object has a given set of `key:value` pairs.
4572  _.isMatch = function(object, attrs) {
4573    var keys = _.keys(attrs), length = keys.length;
4574    if (object == null) return !length;
4575    var obj = Object(object);
4576    for (var i = 0; i < length; i++) {
4577      var key = keys[i];
4578      if (attrs[key] !== obj[key] || !(key in obj)) return false;
4579    }
4580    return true;
4581  };
4582
4583
4584  // Internal recursive comparison function for `isEqual`.
4585  var eq = function(a, b, aStack, bStack) {
4586    // Identical objects are equal. `0 === -0`, but they aren't identical.
4587    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
4588    if (a === b) return a !== 0 || 1 / a === 1 / b;
4589    // A strict comparison is necessary because `null == undefined`.
4590    if (a == null || b == null) return a === b;
4591    // Unwrap any wrapped objects.
4592    if (a instanceof _) a = a._wrapped;
4593    if (b instanceof _) b = b._wrapped;
4594    // Compare `[[Class]]` names.
4595    var className = toString.call(a);
4596    if (className !== toString.call(b)) return false;
4597    switch (className) {
4598      // Strings, numbers, regular expressions, dates, and booleans are compared by value.
4599      case '[object RegExp]':
4600      // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
4601      case '[object String]':
4602        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
4603        // equivalent to `new String("5")`.
4604        return '' + a === '' + b;
4605      case '[object Number]':
4606        // `NaN`s are equivalent, but non-reflexive.
4607        // Object(NaN) is equivalent to NaN
4608        if (+a !== +a) return +b !== +b;
4609        // An `egal` comparison is performed for other numeric values.
4610        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
4611      case '[object Date]':
4612      case '[object Boolean]':
4613        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
4614        // millisecond representations. Note that invalid dates with millisecond representations
4615        // of `NaN` are not equivalent.
4616        return +a === +b;
4617    }
4618
4619    var areArrays = className === '[object Array]';
4620    if (!areArrays) {
4621      if (typeof a != 'object' || typeof b != 'object') return false;
4622
4623      // Objects with different constructors are not equivalent, but `Object`s or `Array`s
4624      // from different frames are.
4625      var aCtor = a.constructor, bCtor = b.constructor;
4626      if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
4627                               _.isFunction(bCtor) && bCtor instanceof bCtor)
4628                          && ('constructor' in a && 'constructor' in b)) {
4629        return false;
4630      }
4631    }
4632    // Assume equality for cyclic structures. The algorithm for detecting cyclic
4633    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
4634
4635    // Initializing stack of traversed objects.
4636    // It's done here since we only need them for objects and arrays comparison.
4637    aStack = aStack || [];
4638    bStack = bStack || [];
4639    var length = aStack.length;
4640    while (length--) {
4641      // Linear search. Performance is inversely proportional to the number of
4642      // unique nested structures.
4643      if (aStack[length] === a) return bStack[length] === b;
4644    }
4645
4646    // Add the first object to the stack of traversed objects.
4647    aStack.push(a);
4648    bStack.push(b);
4649
4650    // Recursively compare objects and arrays.
4651    if (areArrays) {
4652      // Compare array lengths to determine if a deep comparison is necessary.
4653      length = a.length;
4654      if (length !== b.length) return false;
4655      // Deep compare the contents, ignoring non-numeric properties.
4656      while (length--) {
4657        if (!eq(a[length], b[length], aStack, bStack)) return false;
4658      }
4659    } else {
4660      // Deep compare objects.
4661      var keys = _.keys(a), key;
4662      length = keys.length;
4663      // Ensure that both objects contain the same number of properties before comparing deep equality.
4664      if (_.keys(b).length !== length) return false;
4665      while (length--) {
4666        // Deep compare each member
4667        key = keys[length];
4668        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
4669      }
4670    }
4671    // Remove the first object from the stack of traversed objects.
4672    aStack.pop();
4673    bStack.pop();
4674    return true;
4675  };
4676
4677  // Perform a deep comparison to check if two objects are equal.
4678  _.isEqual = function(a, b) {
4679    return eq(a, b);
4680  };
4681
4682  // Is a given array, string, or object empty?
4683  // An "empty" object has no enumerable own-properties.
4684  _.isEmpty = function(obj) {
4685    if (obj == null) return true;
4686    if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
4687    return _.keys(obj).length === 0;
4688  };
4689
4690  // Is a given value a DOM element?
4691  _.isElement = function(obj) {
4692    return !!(obj && obj.nodeType === 1);
4693  };
4694
4695  // Is a given value an array?
4696  // Delegates to ECMA5's native Array.isArray
4697  _.isArray = nativeIsArray || function(obj) {
4698    return toString.call(obj) === '[object Array]';
4699  };
4700
4701  // Is a given variable an object?
4702  _.isObject = function(obj) {
4703    var type = typeof obj;
4704    return type === 'function' || type === 'object' && !!obj;
4705  };
4706
4707  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
4708  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
4709    _['is' + name] = function(obj) {
4710      return toString.call(obj) === '[object ' + name + ']';
4711    };
4712  });
4713
4714  // Define a fallback version of the method in browsers (ahem, IE < 9), where
4715  // there isn't any inspectable "Arguments" type.
4716  if (!_.isArguments(arguments)) {
4717    _.isArguments = function(obj) {
4718      return _.has(obj, 'callee');
4719    };
4720  }
4721
4722  // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
4723  // IE 11 (#1621), and in Safari 8 (#1929).
4724  if (typeof /./ != 'function' && typeof Int8Array != 'object') {
4725    _.isFunction = function(obj) {
4726      return typeof obj == 'function' || false;
4727    };
4728  }
4729
4730  // Is a given object a finite number?
4731  _.isFinite = function(obj) {
4732    return isFinite(obj) && !isNaN(parseFloat(obj));
4733  };
4734
4735  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
4736  _.isNaN = function(obj) {
4737    return _.isNumber(obj) && obj !== +obj;
4738  };
4739
4740  // Is a given value a boolean?
4741  _.isBoolean = function(obj) {
4742    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
4743  };
4744
4745  // Is a given value equal to null?
4746  _.isNull = function(obj) {
4747    return obj === null;
4748  };
4749
4750  // Is a given variable undefined?
4751  _.isUndefined = function(obj) {
4752    return obj === void 0;
4753  };
4754
4755  // Shortcut function for checking if an object has a given property directly
4756  // on itself (in other words, not on a prototype).
4757  _.has = function(obj, key) {
4758    return obj != null && hasOwnProperty.call(obj, key);
4759  };
4760
4761  // Utility Functions
4762  // -----------------
4763
4764  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
4765  // previous owner. Returns a reference to the Underscore object.
4766  _.noConflict = function() {
4767    root._ = previousUnderscore;
4768    return this;
4769  };
4770
4771  // Keep the identity function around for default iteratees.
4772  _.identity = function(value) {
4773    return value;
4774  };
4775
4776  // Predicate-generating functions. Often useful outside of Underscore.
4777  _.constant = function(value) {
4778    return function() {
4779      return value;
4780    };
4781  };
4782
4783  _.noop = function(){};
4784
4785  _.property = property;
4786
4787  // Generates a function for a given object that returns a given property.
4788  _.propertyOf = function(obj) {
4789    return obj == null ? function(){} : function(key) {
4790      return obj[key];
4791    };
4792  };
4793
4794  // Returns a predicate for checking whether an object has a given set of
4795  // `key:value` pairs.
4796  _.matcher = _.matches = function(attrs) {
4797    attrs = _.extendOwn({}, attrs);
4798    return function(obj) {
4799      return _.isMatch(obj, attrs);
4800    };
4801  };
4802
4803  // Run a function **n** times.
4804  _.times = function(n, iteratee, context) {
4805    var accum = Array(Math.max(0, n));
4806    iteratee = optimizeCb(iteratee, context, 1);
4807    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
4808    return accum;
4809  };
4810
4811  // Return a random integer between min and max (inclusive).
4812  _.random = function(min, max) {
4813    if (max == null) {
4814      max = min;
4815      min = 0;
4816    }
4817    return min + Math.floor(Math.random() * (max - min + 1));
4818  };
4819
4820  // A (possibly faster) way to get the current timestamp as an integer.
4821  _.now = Date.now || function() {
4822    return new Date().getTime();
4823  };
4824
4825   // List of HTML entities for escaping.
4826  var escapeMap = {
4827    '&': '&amp;',
4828    '<': '&lt;',
4829    '>': '&gt;',
4830    '"': '&quot;',
4831    "'": '&#x27;',
4832    '`': '&#x60;'
4833  };
4834  var unescapeMap = _.invert(escapeMap);
4835
4836  // Functions for escaping and unescaping strings to/from HTML interpolation.
4837  var createEscaper = function(map) {
4838    var escaper = function(match) {
4839      return map[match];
4840    };
4841    // Regexes for identifying a key that needs to be escaped
4842    var source = '(?:' + _.keys(map).join('|') + ')';
4843    var testRegexp = RegExp(source);
4844    var replaceRegexp = RegExp(source, 'g');
4845    return function(string) {
4846      string = string == null ? '' : '' + string;
4847      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
4848    };
4849  };
4850  _.escape = createEscaper(escapeMap);
4851  _.unescape = createEscaper(unescapeMap);
4852
4853  // If the value of the named `property` is a function then invoke it with the
4854  // `object` as context; otherwise, return it.
4855  _.result = function(object, property, fallback) {
4856    var value = object == null ? void 0 : object[property];
4857    if (value === void 0) {
4858      value = fallback;
4859    }
4860    return _.isFunction(value) ? value.call(object) : value;
4861  };
4862
4863  // Generate a unique integer id (unique within the entire client session).
4864  // Useful for temporary DOM ids.
4865  var idCounter = 0;
4866  _.uniqueId = function(prefix) {
4867    var id = ++idCounter + '';
4868    return prefix ? prefix + id : id;
4869  };
4870
4871  // By default, Underscore uses ERB-style template delimiters, change the
4872  // following template settings to use alternative delimiters.
4873  _.templateSettings = {
4874    evaluate    : /<%([\s\S]+?)%>/g,
4875    interpolate : /<%=([\s\S]+?)%>/g,
4876    escape      : /<%-([\s\S]+?)%>/g
4877  };
4878
4879  // When customizing `templateSettings`, if you don't want to define an
4880  // interpolation, evaluation or escaping regex, we need one that is
4881  // guaranteed not to match.
4882  var noMatch = /(.)^/;
4883
4884  // Certain characters need to be escaped so that they can be put into a
4885  // string literal.
4886  var escapes = {
4887    "'":      "'",
4888    '\\':     '\\',
4889    '\r':     'r',
4890    '\n':     'n',
4891    '\u2028': 'u2028',
4892    '\u2029': 'u2029'
4893  };
4894
4895  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
4896
4897  var escapeChar = function(match) {
4898    return '\\' + escapes[match];
4899  };
4900
4901  // JavaScript micro-templating, similar to John Resig's implementation.
4902  // Underscore templating handles arbitrary delimiters, preserves whitespace,
4903  // and correctly escapes quotes within interpolated code.
4904  // NB: `oldSettings` only exists for backwards compatibility.
4905  _.template = function(text, settings, oldSettings) {
4906    if (!settings && oldSettings) settings = oldSettings;
4907    settings = _.defaults({}, settings, _.templateSettings);
4908
4909    // Combine delimiters into one regular expression via alternation.
4910    var matcher = RegExp([
4911      (settings.escape || noMatch).source,
4912      (settings.interpolate || noMatch).source,
4913      (settings.evaluate || noMatch).source
4914    ].join('|') + '|$', 'g');
4915
4916    // Compile the template source, escaping string literals appropriately.
4917    var index = 0;
4918    var source = "__p+='";
4919    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
4920      source += text.slice(index, offset).replace(escaper, escapeChar);
4921      index = offset + match.length;
4922
4923      if (escape) {
4924        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
4925      } else if (interpolate) {
4926        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
4927      } else if (evaluate) {
4928        source += "';\n" + evaluate + "\n__p+='";
4929      }
4930
4931      // Adobe VMs need the match returned to produce the correct offest.
4932      return match;
4933    });
4934    source += "';\n";
4935
4936    // If a variable is not specified, place data values in local scope.
4937    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
4938
4939    source = "var __t,__p='',__j=Array.prototype.join," +
4940      "print=function(){__p+=__j.call(arguments,'');};\n" +
4941      source + 'return __p;\n';
4942
4943    try {
4944      var render = new Function(settings.variable || 'obj', '_', source);
4945    } catch (e) {
4946      e.source = source;
4947      throw e;
4948    }
4949
4950    var template = function(data) {
4951      return render.call(this, data, _);
4952    };
4953
4954    // Provide the compiled source as a convenience for precompilation.
4955    var argument = settings.variable || 'obj';
4956    template.source = 'function(' + argument + '){\n' + source + '}';
4957
4958    return template;
4959  };
4960
4961  // Add a "chain" function. Start chaining a wrapped Underscore object.
4962  _.chain = function(obj) {
4963    var instance = _(obj);
4964    instance._chain = true;
4965    return instance;
4966  };
4967
4968  // OOP
4969  // ---------------
4970  // If Underscore is called as a function, it returns a wrapped object that
4971  // can be used OO-style. This wrapper holds altered versions of all the
4972  // underscore functions. Wrapped objects may be chained.
4973
4974  // Helper function to continue chaining intermediate results.
4975  var result = function(instance, obj) {
4976    return instance._chain ? _(obj).chain() : obj;
4977  };
4978
4979  // Add your own custom functions to the Underscore object.
4980  _.mixin = function(obj) {
4981    _.each(_.functions(obj), function(name) {
4982      var func = _[name] = obj[name];
4983      _.prototype[name] = function() {
4984        var args = [this._wrapped];
4985        push.apply(args, arguments);
4986        return result(this, func.apply(_, args));
4987      };
4988    });
4989  };
4990
4991  // Add all of the Underscore functions to the wrapper object.
4992  _.mixin(_);
4993
4994  // Add all mutator Array functions to the wrapper.
4995  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
4996    var method = ArrayProto[name];
4997    _.prototype[name] = function() {
4998      var obj = this._wrapped;
4999      method.apply(obj, arguments);
5000      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
5001      return result(this, obj);
5002    };
5003  });
5004
5005  // Add all accessor Array functions to the wrapper.
5006  _.each(['concat', 'join', 'slice'], function(name) {
5007    var method = ArrayProto[name];
5008    _.prototype[name] = function() {
5009      return result(this, method.apply(this._wrapped, arguments));
5010    };
5011  });
5012
5013  // Extracts the result from a wrapped and chained object.
5014  _.prototype.value = function() {
5015    return this._wrapped;
5016  };
5017
5018  // Provide unwrapping proxy for some methods used in engine operations
5019  // such as arithmetic and JSON stringification.
5020  _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
5021
5022  _.prototype.toString = function() {
5023    return '' + this._wrapped;
5024  };
5025
5026  // AMD registration happens at the end for compatibility with AMD loaders
5027  // that may not enforce next-turn semantics on modules. Even though general
5028  // practice for AMD registration is to be anonymous, underscore registers
5029  // as a named module because, like jQuery, it is a base library that is
5030  // popular enough to be bundled in a third party lib, but not be part of
5031  // an AMD load request. Those cases could generate an error when an
5032  // anonymous define() is called outside of a loader request.
5033  if (typeof define === 'function' && define.amd) {
5034    define('underscore', [], function() {
5035      return _;
5036    });
5037  }
5038}.call(this));
5039
5040/**
5041 * @license AngularJS v1.2.25
5042 * (c) 2010-2014 Google, Inc. http://angularjs.org
5043 * License: MIT
5044 */
5045(function(window, document, undefined) {'use strict';
5046
5047/**
5048 * @description
5049 *
5050 * This object provides a utility for producing rich Error messages within
5051 * Angular. It can be called as follows:
5052 *
5053 * var exampleMinErr = minErr('example');
5054 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
5055 *
5056 * The above creates an instance of minErr in the example namespace. The
5057 * resulting error will have a namespaced error code of example.one.  The
5058 * resulting error will replace {0} with the value of foo, and {1} with the
5059 * value of bar. The object is not restricted in the number of arguments it can
5060 * take.
5061 *
5062 * If fewer arguments are specified than necessary for interpolation, the extra
5063 * interpolation markers will be preserved in the final string.
5064 *
5065 * Since data will be parsed statically during a build step, some restrictions
5066 * are applied with respect to how minErr instances are created and called.
5067 * Instances should have names of the form namespaceMinErr for a minErr created
5068 * using minErr('namespace') . Error codes, namespaces and template strings
5069 * should all be static strings, not variables or general expressions.
5070 *
5071 * @param {string} module The namespace to use for the new minErr instance.
5072 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
5073 */
5074
5075function minErr(module) {
5076  return function () {
5077    var code = arguments[0],
5078      prefix = '[' + (module ? module + ':' : '') + code + '] ',
5079      template = arguments[1],
5080      templateArgs = arguments,
5081      stringify = function (obj) {
5082        if (typeof obj === 'function') {
5083          return obj.toString().replace(/ \{[\s\S]*$/, '');
5084        } else if (typeof obj === 'undefined') {
5085          return 'undefined';
5086        } else if (typeof obj !== 'string') {
5087          return JSON.stringify(obj);
5088        }
5089        return obj;
5090      },
5091      message, i;
5092
5093    message = prefix + template.replace(/\{\d+\}/g, function (match) {
5094      var index = +match.slice(1, -1), arg;
5095
5096      if (index + 2 < templateArgs.length) {
5097        arg = templateArgs[index + 2];
5098        if (typeof arg === 'function') {
5099          return arg.toString().replace(/ ?\{[\s\S]*$/, '');
5100        } else if (typeof arg === 'undefined') {
5101          return 'undefined';
5102        } else if (typeof arg !== 'string') {
5103          return toJson(arg);
5104        }
5105        return arg;
5106      }
5107      return match;
5108    });
5109
5110    message = message + '\nhttp://errors.angularjs.org/1.2.25/' +
5111      (module ? module + '/' : '') + code;
5112    for (i = 2; i < arguments.length; i++) {
5113      message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
5114        encodeURIComponent(stringify(arguments[i]));
5115    }
5116
5117    return new Error(message);
5118  };
5119}
5120
5121/* We need to tell jshint what variables are being exported */
5122/* global angular: true,
5123    msie: true,
5124    jqLite: true,
5125    jQuery: true,
5126    slice: true,
5127    push: true,
5128    toString: true,
5129    ngMinErr: true,
5130    angularModule: true,
5131    nodeName_: true,
5132    uid: true,
5133    VALIDITY_STATE_PROPERTY: true,
5134
5135    lowercase: true,
5136    uppercase: true,
5137    manualLowercase: true,
5138    manualUppercase: true,
5139    nodeName_: true,
5140    isArrayLike: true,
5141    forEach: true,
5142    sortedKeys: true,
5143    forEachSorted: true,
5144    reverseParams: true,
5145    nextUid: true,
5146    setHashKey: true,
5147    extend: true,
5148    int: true,
5149    inherit: true,
5150    noop: true,
5151    identity: true,
5152    valueFn: true,
5153    isUndefined: true,
5154    isDefined: true,
5155    isObject: true,
5156    isString: true,
5157    isNumber: true,
5158    isDate: true,
5159    isArray: true,
5160    isFunction: true,
5161    isRegExp: true,
5162    isWindow: true,
5163    isScope: true,
5164    isFile: true,
5165    isBlob: true,
5166    isBoolean: true,
5167    isPromiseLike: true,
5168    trim: true,
5169    isElement: true,
5170    makeMap: true,
5171    map: true,
5172    size: true,
5173    includes: true,
5174    indexOf: true,
5175    arrayRemove: true,
5176    isLeafNode: true,
5177    copy: true,
5178    shallowCopy: true,
5179    equals: true,
5180    csp: true,
5181    concat: true,
5182    sliceArgs: true,
5183    bind: true,
5184    toJsonReplacer: true,
5185    toJson: true,
5186    fromJson: true,
5187    toBoolean: true,
5188    startingTag: true,
5189    tryDecodeURIComponent: true,
5190    parseKeyValue: true,
5191    toKeyValue: true,
5192    encodeUriSegment: true,
5193    encodeUriQuery: true,
5194    angularInit: true,
5195    bootstrap: true,
5196    snake_case: true,
5197    bindJQuery: true,
5198    assertArg: true,
5199    assertArgFn: true,
5200    assertNotHasOwnProperty: true,
5201    getter: true,
5202    getBlockElements: true,
5203    hasOwnProperty: true,
5204*/
5205
5206////////////////////////////////////
5207
5208/**
5209 * @ngdoc module
5210 * @name ng
5211 * @module ng
5212 * @description
5213 *
5214 * # ng (core module)
5215 * The ng module is loaded by default when an AngularJS application is started. The module itself
5216 * contains the essential components for an AngularJS application to function. The table below
5217 * lists a high level breakdown of each of the services/factories, filters, directives and testing
5218 * components available within this core module.
5219 *
5220 * <div doc-module-components="ng"></div>
5221 */
5222
5223// The name of a form control's ValidityState property.
5224// This is used so that it's possible for internal tests to create mock ValidityStates.
5225var VALIDITY_STATE_PROPERTY = 'validity';
5226
5227/**
5228 * @ngdoc function
5229 * @name angular.lowercase
5230 * @module ng
5231 * @kind function
5232 *
5233 * @description Converts the specified string to lowercase.
5234 * @param {string} string String to be converted to lowercase.
5235 * @returns {string} Lowercased string.
5236 */
5237var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
5238var hasOwnProperty = Object.prototype.hasOwnProperty;
5239
5240/**
5241 * @ngdoc function
5242 * @name angular.uppercase
5243 * @module ng
5244 * @kind function
5245 *
5246 * @description Converts the specified string to uppercase.
5247 * @param {string} string String to be converted to uppercase.
5248 * @returns {string} Uppercased string.
5249 */
5250var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
5251
5252
5253var manualLowercase = function(s) {
5254  /* jshint bitwise: false */
5255  return isString(s)
5256      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
5257      : s;
5258};
5259var manualUppercase = function(s) {
5260  /* jshint bitwise: false */
5261  return isString(s)
5262      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
5263      : s;
5264};
5265
5266
5267// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
5268// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
5269// with correct but slower alternatives.
5270if ('i' !== 'I'.toLowerCase()) {
5271  lowercase = manualLowercase;
5272  uppercase = manualUppercase;
5273}
5274
5275
5276var /** holds major version number for IE or NaN for real browsers */
5277    msie,
5278    jqLite,           // delay binding since jQuery could be loaded after us.
5279    jQuery,           // delay binding
5280    slice             = [].slice,
5281    push              = [].push,
5282    toString          = Object.prototype.toString,
5283    ngMinErr          = minErr('ng'),
5284
5285    /** @name angular */
5286    angular           = window.angular || (window.angular = {}),
5287    angularModule,
5288    nodeName_,
5289    uid               = ['0', '0', '0'];
5290
5291/**
5292 * IE 11 changed the format of the UserAgent string.
5293 * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
5294 */
5295msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
5296if (isNaN(msie)) {
5297  msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
5298}
5299
5300
5301/**
5302 * @private
5303 * @param {*} obj
5304 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
5305 *                   String ...)
5306 */
5307function isArrayLike(obj) {
5308  if (obj == null || isWindow(obj)) {
5309    return false;
5310  }
5311
5312  var length = obj.length;
5313
5314  if (obj.nodeType === 1 && length) {
5315    return true;
5316  }
5317
5318  return isString(obj) || isArray(obj) || length === 0 ||
5319         typeof length === 'number' && length > 0 && (length - 1) in obj;
5320}
5321
5322/**
5323 * @ngdoc function
5324 * @name angular.forEach
5325 * @module ng
5326 * @kind function
5327 *
5328 * @description
5329 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
5330 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
5331 * is the value of an object property or an array element and `key` is the object property key or
5332 * array element index. Specifying a `context` for the function is optional.
5333 *
5334 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
5335 * using the `hasOwnProperty` method.
5336 *
5337   ```js
5338     var values = {name: 'misko', gender: 'male'};
5339     var log = [];
5340     angular.forEach(values, function(value, key) {
5341       this.push(key + ': ' + value);
5342     }, log);
5343     expect(log).toEqual(['name: misko', 'gender: male']);
5344   ```
5345 *
5346 * @param {Object|Array} obj Object to iterate over.
5347 * @param {Function} iterator Iterator function.
5348 * @param {Object=} context Object to become context (`this`) for the iterator function.
5349 * @returns {Object|Array} Reference to `obj`.
5350 */
5351function forEach(obj, iterator, context) {
5352  var key;
5353  if (obj) {
5354    if (isFunction(obj)) {
5355      for (key in obj) {
5356        // Need to check if hasOwnProperty exists,
5357        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
5358        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
5359          iterator.call(context, obj[key], key);
5360        }
5361      }
5362    } else if (isArray(obj) || isArrayLike(obj)) {
5363      for (key = 0; key < obj.length; key++) {
5364        iterator.call(context, obj[key], key);
5365      }
5366    }
5366 else if (obj.forEach && obj.forEach !== forEach) {
5367        obj.forEach(iterator, context);
5368    } else {
5369      for (key in obj) {
5370        if (obj.hasOwnProperty(key)) {
5371          iterator.call(context, obj[key], key);
5372        }
5373      }
5374    }
5375  }
5376  return obj;
5377}
5378
5379function sortedKeys(obj) {
5380  var keys = [];
5381  for (var key in obj) {
5382    if (obj.hasOwnProperty(key)) {
5383      keys.push(key);
5384    }
5385  }
5386  return keys.sort();
5387}
5388
5389function forEachSorted(obj, iterator, context) {
5390  var keys = sortedKeys(obj);
5391  for ( var i = 0; i < keys.length; i++) {
5392    iterator.call(context, obj[keys[i]], keys[i]);
5393  }
5394  return keys;
5395}
5396
5397
5398/**
5399 * when using forEach the params are value, key, but it is often useful to have key, value.
5400 * @param {function(string, *)} iteratorFn
5401 * @returns {function(*, string)}
5402 */
5403function reverseParams(iteratorFn) {
5404  return function(value, key) { iteratorFn(key, value); };
5405}
5406
5407/**
5408 * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
5409 * characters such as '012ABC'. The reason why we are not using simply a number counter is that
5410 * the number string gets longer over time, and it can also overflow, where as the nextId
5411 * will grow much slower, it is a string, and it will never overflow.
5412 *
5413 * @returns {string} an unique alpha-numeric string
5414 */
5415function nextUid() {
5416  var index = uid.length;
5417  var digit;
5418
5419  while(index) {
5420    index--;
5421    digit = uid[index].charCodeAt(0);
5422    if (digit == 57 /*'9'*/) {
5423      uid[index] = 'A';
5424      return uid.join('');
5425    }
5426    if (digit == 90  /*'Z'*/) {
5427      uid[index] = '0';
5428    } else {
5429      uid[index] = String.fromCharCode(digit + 1);
5430      return uid.join('');
5431    }
5432  }
5433  uid.unshift('0');
5434  return uid.join('');
5435}
5436
5437
5438/**
5439 * Set or clear the hashkey for an object.
5440 * @param obj object
5441 * @param h the hashkey (!truthy to delete the hashkey)
5442 */
5443function setHashKey(obj, h) {
5444  if (h) {
5445    obj.$$hashKey = h;
5446  }
5447  else {
5448    delete obj.$$hashKey;
5449  }
5450}
5451
5452/**
5453 * @ngdoc function
5454 * @name angular.extend
5455 * @module ng
5456 * @kind function
5457 *
5458 * @description
5459 * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
5460 * to `dst`. You can specify multiple `src` objects.
5461 *
5462 * @param {Object} dst Destination object.
5463 * @param {...Object} src Source object(s).
5464 * @returns {Object} Reference to `dst`.
5465 */
5466function extend(dst) {
5467  var h = dst.$$hashKey;
5468  forEach(arguments, function(obj) {
5469    if (obj !== dst) {
5470      forEach(obj, function(value, key) {
5471        dst[key] = value;
5472      });
5473    }
5474  });
5475
5476  setHashKey(dst,h);
5477  return dst;
5478}
5479
5480function int(str) {
5481  return parseInt(str, 10);
5482}
5483
5484
5485function inherit(parent, extra) {
5486  return extend(new (extend(function() {}, {prototype:parent}))(), extra);
5487}
5488
5489/**
5490 * @ngdoc function
5491 * @name angular.noop
5492 * @module ng
5493 * @kind function
5494 *
5495 * @description
5496 * A function that performs no operations. This function can be useful when writing code in the
5497 * functional style.
5498   ```js
5499     function foo(callback) {
5500       var result = calculateResult();
5501       (callback || angular.noop)(result);
5502     }
5503   ```
5504 */
5505function noop() {}
5506noop.$inject = [];
5507
5508
5509/**
5510 * @ngdoc function
5511 * @name angular.identity
5512 * @module ng
5513 * @kind function
5514 *
5515 * @description
5516 * A function that returns its first argument. This function is useful when writing code in the
5517 * functional style.
5518 *
5519   ```js
5520     function transformer(transformationFn, value) {
5521       return (transformationFn || angular.identity)(value);
5522     };
5523   ```
5524 */
5525function identity($) {return $;}
5526identity.$inject = [];
5527
5528
5529function valueFn(value) {return function() {return value;};}
5530
5531/**
5532 * @ngdoc function
5533 * @name angular.isUndefined
5534 * @module ng
5535 * @kind function
5536 *
5537 * @description
5538 * Determines if a reference is undefined.
5539 *
5540 * @param {*} value Reference to check.
5541 * @returns {boolean} True if `value` is undefined.
5542 */
5543function isUndefined(value){return typeof value === 'undefined';}
5544
5545
5546/**
5547 * @ngdoc function
5548 * @name angular.isDefined
5549 * @module ng
5550 * @kind function
5551 *
5552 * @description
5553 * Determines if a reference is defined.
5554 *
5555 * @param {*} value Reference to check.
5556 * @returns {boolean} True if `value` is defined.
5557 */
5558function isDefined(value){return typeof value !== 'undefined';}
5559
5560
5561/**
5562 * @ngdoc function
5563 * @name angular.isObject
5564 * @module ng
5565 * @kind function
5566 *
5567 * @description
5568 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
5569 * considered to be objects. Note that JavaScript arrays are objects.
5570 *
5571 * @param {*} value Reference to check.
5572 * @returns {boolean} True if `value` is an `Object` but not `null`.
5573 */
5574function isObject(value){return value != null && typeof value === 'object';}
5575
5576
5577/**
5578 * @ngdoc function
5579 * @name angular.isString
5580 * @module ng
5581 * @kind function
5582 *
5583 * @description
5584 * Determines if a reference is a `String`.
5585 *
5586 * @param {*} value Reference to check.
5587 * @returns {boolean} True if `value` is a `String`.
5588 */
5589function isString(value){return typeof value === 'string';}
5590
5591
5592/**
5593 * @ngdoc function
5594 * @name angular.isNumber
5595 * @module ng
5596 * @kind function
5597 *
5598 * @description
5599 * Determines if a reference is a `Number`.
5600 *
5601 * @param {*} value Reference to check.
5602 * @returns {boolean} True if `value` is a `Number`.
5603 */
5604function isNumber(value){return typeof value === 'number';}
5605
5606
5607/**
5608 * @ngdoc function
5609 * @name angular.isDate
5610 * @module ng
5611 * @kind function
5612 *
5613 * @description
5614 * Determines if a value is a date.
5615 *
5616 * @param {*} value Reference to check.
5617 * @returns {boolean} True if `value` is a `Date`.
5618 */
5619function isDate(value) {
5620  return toString.call(value) === '[object Date]';
5621}
5622
5623
5624/**
5625 * @ngdoc function
5626 * @name angular.isArray
5627 * @module ng
5628 * @kind function
5629 *
5630 * @description
5631 * Determines if a reference is an `Array`.
5632 *
5633 * @param {*} value Reference to check.
5634 * @returns {boolean} True if `value` is an `Array`.
5635 */
5636var isArray = (function() {
5637  if (!isFunction(Array.isArray)) {
5638    return function(value) {
5639      return toString.call(value) === '[object Array]';
5640    };
5641  }
5642  return Array.isArray;
5643})();
5644
5645/**
5646 * @ngdoc function
5647 * @name angular.isFunction
5648 * @module ng
5649 * @kind function
5650 *
5651 * @description
5652 * Determines if a reference is a `Function`.
5653 *
5654 * @param {*} value Reference to check.
5655 * @returns {boolean} True if `value` is a `Function`.
5656 */
5657function isFunction(value){return typeof value === 'function';}
5658
5659
5660/**
5661 * Determines if a value is a regular expression object.
5662 *
5663 * @private
5664 * @param {*} value Reference to check.
5665 * @returns {boolean} True if `value` is a `RegExp`.
5666 */
5667function isRegExp(value) {
5668  return toString.call(value) === '[object RegExp]';
5669}
5670
5671
5672/**
5673 * Checks if `obj` is a window object.
5674 *
5675 * @private
5676 * @param {*} obj Object to check
5677 * @returns {boolean} True if `obj` is a window obj.
5678 */
5679function isWindow(obj) {
5680  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
5681}
5682
5683
5684function isScope(obj) {
5685  return obj && obj.$evalAsync && obj.$watch;
5686}
5687
5688
5689function isFile(obj) {
5690  return toString.call(obj) === '[object File]';
5691}
5692
5693
5694function isBlob(obj) {
5695  return toString.call(obj) === '[object Blob]';
5696}
5697
5698
5699function isBoolean(value) {
5700  return typeof value === 'boolean';
5701}
5702
5703
5704function isPromiseLike(obj) {
5705  return obj && isFunction(obj.then);
5706}
5707
5708
5709var trim = (function() {
5710  // native trim is way faster: http://jsperf.com/angular-trim-test
5711  // but IE doesn't have it... :-(
5712  // TODO: we should move this into IE/ES5 polyfill
5713  if (!String.prototype.trim) {
5714    return function(value) {
5715      return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
5716    };
5717  }
5718  return function(value) {
5719    return isString(value) ? value.trim() : value;
5720  };
5721})();
5722
5723
5724/**
5725 * @ngdoc function
5726 * @name angular.isElement
5727 * @module ng
5728 * @kind function
5729 *
5730 * @description
5731 * Determines if a reference is a DOM element (or wrapped jQuery element).
5732 *
5733 * @param {*} value Reference to check.
5734 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
5735 */
5736function isElement(node) {
5737  return !!(node &&
5738    (node.nodeName  // we are a direct element
5739    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
5740}
5741
5742/**
5743 * @param str 'key1,key2,...'
5744 * @returns {object} in the form of {key1:true, key2:true, ...}
5745 */
5746function makeMap(str) {
5747  var obj = {}, items = str.split(","), i;
5748  for ( i = 0; i < items.length; i++ )
5749    obj[ items[i] ] = true;
5750  return obj;
5751}
5752
5753
5754if (msie < 9) {
5755  nodeName_ = function(element) {
5756    element = element.nodeName ? element : element[0];
5757    return (element.scopeName && element.scopeName != 'HTML')
5758      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
5759  };
5760} else {
5761  nodeName_ = function(element) {
5762    return element.nodeName ? element.nodeName : element[0].nodeName;
5763  };
5764}
5765
5766
5767function map(obj, iterator, context) {
5768  var results = [];
5769  forEach(obj, function(value, index, list) {
5770    results.push(iterator.call(context, value, index, list));
5771  });
5772  return results;
5773}
5774
5775
5776/**
5777 * @description
5778 * Determines the number of elements in an array, the number of properties an object has, or
5779 * the length of a string.
5780 *
5781 * Note: This function is used to augment the Object type in Angular expressions. See
5782 * {@link angular.Object} for more information about Angular arrays.
5783 *
5784 * @param {Object|Array|string} obj Object, array, or string to inspect.
5785 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
5786 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
5787 */
5788function size(obj, ownPropsOnly) {
5789  var count = 0, key;
5790
5791  if (isArray(obj) || isString(obj)) {
5792    return obj.length;
5793  } else if (isObject(obj)) {
5794    for (key in obj)
5795      if (!ownPropsOnly || obj.hasOwnProperty(key))
5796        count++;
5797  }
5798
5799  return count;
5800}
5801
5802
5803function includes(array, obj) {
5804  return indexOf(array, obj) != -1;
5805}
5806
5807function indexOf(array, obj) {
5808  if (array.indexOf) return array.indexOf(obj);
5809
5810  for (var i = 0; i < array.length; i++) {
5811    if (obj === array[i]) return i;
5812  }
5813  return -1;
5814}
5815
5816function arrayRemove(array, value) {
5817  var index = indexOf(array, value);
5818  if (index >=0)
5819    array.splice(index, 1);
5820  return value;
5821}
5822
5823function isLeafNode (node) {
5824  if (node) {
5825    switch (node.nodeName) {
5826    case "OPTION":
5827    case "PRE":
5828    case "TITLE":
5829      return true;
5830    }
5831  }
5832  return false;
5833}
5834
5835/**
5836 * @ngdoc function
5837 * @name angular.copy
5838 * @module ng
5839 * @kind function
5840 *
5841 * @description
5842 * Creates a deep copy of `source`, which should be an object or an array.
5843 *
5844 * * If no destination is supplied, a copy of the object or array is created.
5845 * * If a destination is provided, all of its elements (for array) or properties (for objects)
5846 *   are deleted and then all elements/properties from the source are copied to it.
5847 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
5848 * * If `source` is identical to 'destination' an exception will be thrown.
5849 *
5850 * @param {*} source The source that will be used to make a copy.
5851 *                   Can be any type, including primitives, `null`, and `undefined`.
5852 * @param {(Object|Array)=} destination Destination into which the source is copied. If
5853 *     provided, must be of the same type as `source`.
5854 * @returns {*} The copy or updated `destination`, if `destination` was specified.
5855 *
5856 * @example
5857 <example module="copyExample">
5858 <file name="index.html">
5859 <div ng-controller="ExampleController">
5860 <form novalidate class="simple-form">
5861 Name: <input type="text" ng-model="user.name" /><br />
5862 E-mail: <input type="email" ng-model="user.email" /><br />
5863 Gender: <input type="radio" ng-model="user.gender" value="male" />male
5864 <input type="radio" ng-model="user.gender" value="female" />female<br />
5865 <button ng-click="reset()">RESET</button>
5866 <button ng-click="update(user)">SAVE</button>
5867 </form>
5868 <pre>form = {{user | json}}</pre>
5869 <pre>master = {{master | json}}</pre>
5870 </div>
5871
5872 <script>
5873  angular.module('copyExample', [])
5874    .controller('ExampleController', ['$scope', function($scope) {
5875      $scope.master= {};
5876
5877      $scope.update = function(user) {
5878        // Example with 1 argument
5879        $scope.master= angular.copy(user);
5880      };
5881
5882      $scope.reset = function() {
5883        // Example with 2 arguments
5884        angular.copy($scope.master, $scope.user);
5885      };
5886
5887      $scope.reset();
5888    }]);
5889 </script>
5890 </file>
5891 </example>
5892 */
5893function copy(source, destination, stackSource, stackDest) {
5894  if (isWindow(source) || isScope(source)) {
5895    throw ngMinErr('cpws',
5896      "Can't copy! Making copies of Window or Scope instances is not supported.");
5897  }
5898
5899  if (!destination) {
5900    destination = source;
5901    if (source) {
5902      if (isArray(source)) {
5903        destination = copy(source, [], stackSource, stackDest);
5904      } else if (isDate(source)) {
5905        destination = new Date(source.getTime());
5906      } else if (isRegExp(source)) {
5907        destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
5908        destination.lastIndex = source.lastIndex;
5909      } else if (isObject(source)) {
5910        destination = copy(source, {}, stackSource, stackDest);
5911      }
5912    }
5913  } else {
5914    if (source === destination) throw ngMinErr('cpi',
5915      "Can't copy! Source and destination are identical.");
5916
5917    stackSource = stackSource || [];
5918    stackDest = stackDest || [];
5919
5920    if (isObject(source)) {
5921      var index = indexOf(stackSource, source);
5922      if (index !== -1) return stackDest[index];
5923
5924      stackSource.push(source);
5925      stackDest.push(destination);
5926    }
5927
5928    var result;
5929    if (isArray(source)) {
5930      destination.length = 0;
5931      for ( var i = 0; i < source.length; i++) {
5932        result = copy(source[i], null, stackSource, stackDest);
5933        if (isObject(source[i])) {
5934          stackSource.push(source[i]);
5935          stackDest.push(result);
5936        }
5937        destination.push(result);
5938      }
5939    } else {
5940      var h = destination.$$hashKey;
5941      if (isArray(destination)) {
5942        destination.length = 0;
5943      } else {
5944        forEach(destination, function(value, key) {
5945          delete destination[key];
5946        });
5947      }
5948      for ( var key in source) {
5949        result = copy(source[key], null, stackSource, stackDest);
5950        if (isObject(source[key])) {
5951          stackSource.push(source[key]);
5952          stackDest.push(result);
5953        }
5954        destination[key] = result;
5955      }
5956      setHashKey(destination,h);
5957    }
5958
5959  }
5960  return destination;
5961}
5962
5963/**
5964 * Creates a shallow copy of an object, an array or a primitive
5965 */
5966function shallowCopy(src, dst) {
5967  if (isArray(src)) {
5968    dst = dst || [];
5969
5970    for ( var i = 0; i < src.length; i++) {
5971      dst[i] = src[i];
5972    }
5973  } else if (isObject(src)) {
5974    dst = dst || {};
5975
5976    for (var key in src) {
5977      if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
5978        dst[key] = src[key];
5979      }
5980    }
5981  }
5982
5983  return dst || src;
5984}
5985
5986
5987/**
5988 * @ngdoc function
5989 * @name angular.equals
5990 * @module ng
5991 * @kind function
5992 *
5993 * @description
5994 * Determines if two objects or two values are equivalent. Supports value types, regular
5995 * expressions, arrays and objects.
5996 *
5997 * Two objects or values are considered equivalent if at least one of the following is true:
5998 *
5999 * * Both objects or values pass `===` comparison.
6000 * * Both objects or values are of the same type and all of their properties are equal by
6001 *   comparing them with `angular.equals`.
6002 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
6003 * * Both values represent the same regular expression (In JavaScript,
6004 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
6005 *   representation matches).
6006 *
6007 * During a property comparison, properties of `function` type and properties with names
6008 * that begin with `$` are ignored.
6009 *
6010 * Scope and DOMWindow objects are being compared only by identify (`===`).
6011 *
6012 * @param {*} o1 Object or value to compare.
6013 * @param {*} o2 Object or value to compare.
6014 * @returns {boolean} True if arguments are equal.
6015 */
6016function equals(o1, o2) {
6017  if (o1 === o2) return true;
6018  if (o1 === null || o2 === null) return false;
6019  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
6020  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
6021  if (t1 == t2) {
6022    if (t1 == 'object') {
6023      if (isArray(o1)) {
6024        if (!isArray(o2)) return false;
6025        if ((length = o1.length) == o2.length) {
6026          for(key=0; key<length; key++) {
6027            if (!equals(o1[key], o2[key])) return false;
6028          }
6029          return true;
6030        }
6031      } else if (isDate(o1)) {
6032        if (!isDate(o2)) return false;
6033        return (isNaN(o1.getTime()) && isNaN(o2.getTime())) || (o1.getTime() === o2.getTime());
6034      } else if (isRegExp(o1) && isRegExp(o2)) {
6035        return o1.toString() == o2.toString();
6036      } else {
6037        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
6038        keySet = {};
6039        for(key in o1) {
6040          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
6041          if (!equals(o1[key], o2[key])) return false;
6042          keySet[key] = true;
6043        }
6044        for(key in o2) {
6045          if (!keySet.hasOwnProperty(key) &&
6046              key.charAt(0) !== '$' &&
6047              o2[key] !== undefined &&
6048              !isFunction(o2[key])) return false;
6049        }
6050        return true;
6051      }
6052    }
6053  }
6054  return false;
6055}
6056
6057var csp = function() {
6058  if (isDefined(csp.isActive_)) return csp.isActive_;
6059
6060  var active = !!(document.querySelector('[ng-csp]') ||
6061                  document.querySelector('[data-ng-csp]'));
6062
6063  if (!active) {
6064    try {
6065      /* jshint -W031, -W054 */
6066      new Function('');
6067      /* jshint +W031, +W054 */
6068    } catch (e) {
6069      active = true;
6070    }
6071  }
6072
6073  return (csp.isActive_ = active);
6074};
6075
6076
6077
6078function concat(array1, array2, index) {
6079  return array1.concat(slice.call(array2, index));
6080}
6081
6082function sliceArgs(args, startIndex) {
6083  return slice.call(args, startIndex || 0);
6084}
6085
6086
6087/* jshint -W101 */
6088/**
6089 * @ngdoc function
6090 * @name angular.bind
6091 * @module ng
6092 * @kind function
6093 *
6094 * @description
6095 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
6096 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
6097 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
6098 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
6099 *
6100 * @param {Object} self Context which `fn` should be evaluated in.
6101 * @param {function()} fn Function to be bound.
6102 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
6103 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
6104 */
6105/* jshint +W101 */
6106function bind(self, fn) {
6107  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
6108  if (isFunction(fn) && !(fn instanceof RegExp)) {
6109    return curryArgs.length
6110      ? function() {
6111          return arguments.length
6112            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
6113            : fn.apply(self, curryArgs);
6114        }
6115      : function() {
6116          return arguments.length
6117            ? fn.apply(self, arguments)
6118            : fn.call(self);
6119        };
6120  } else {
6121    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
6122    return fn;
6123  }
6124}
6125
6126
6127function toJsonReplacer(key, value) {
6128  var val = value;
6129
6130  if (typeof key === 'string' && key.charAt(0) === '$') {
6131    val = undefined;
6132  } else if (isWindow(value)) {
6133    val = '$WINDOW';
6134  } else if (value &&  document === value) {
6135    val = '$DOCUMENT';
6136  } else if (isScope(value)) {
6137    val = '$SCOPE';
6138  }
6139
6140  return val;
6141}
6142
6143
6144/**
6145 * @ngdoc function
6146 * @name angular.toJson
6147 * @module ng
6148 * @kind function
6149 *
6150 * @description
6151 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
6152 * stripped since angular uses this notation internally.
6153 *
6154 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
6155 * @param {boolean=}
6155 pretty If set to true, the JSON output will contain newlines and whitespace.
6156 * @returns {string|undefined} JSON-ified string representing `obj`.
6157 */
6158function toJson(obj, pretty) {
6159  if (typeof obj === 'undefined') return undefined;
6160  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
6161}
6162
6163
6164/**
6165 * @ngdoc function
6166 * @name angular.fromJson
6167 * @module ng
6168 * @kind function
6169 *
6170 * @description
6171 * Deserializes a JSON string.
6172 *
6173 * @param {string} json JSON string to deserialize.
6174 * @returns {Object|Array|string|number} Deserialized thingy.
6175 */
6176function fromJson(json) {
6177  return isString(json)
6178      ? JSON.parse(json)
6179      : json;
6180}
6181
6182
6183function toBoolean(value) {
6184  if (typeof value === 'function') {
6185    value = true;
6186  } else if (value && value.length !== 0) {
6187    var v = lowercase("" + value);
6188    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
6189  } else {
6190    value = false;
6191  }
6192  return value;
6193}
6194
6195/**
6196 * @returns {string} Returns the string representation of the element.
6197 */
6198function startingTag(element) {
6199  element = jqLite(element).clone();
6200  try {
6201    // turns out IE does not let you set .html() on elements which
6202    // are not allowed to have children. So we just ignore it.
6203    element.empty();
6204  } catch(e) {}
6205  // As Per DOM Standards
6206  var TEXT_NODE = 3;
6207  var elemHtml = jqLite('<div>').append(element).html();
6208  try {
6209    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
6210        elemHtml.
6211          match(/^(<[^>]+>)/)[1].
6212          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
6213  } catch(e) {
6214    return lowercase(elemHtml);
6215  }
6216
6217}
6218
6219
6220/////////////////////////////////////////////////
6221
6222/**
6223 * Tries to decode the URI component without throwing an exception.
6224 *
6225 * @private
6226 * @param str value potential URI component to check.
6227 * @returns {boolean} True if `value` can be decoded
6228 * with the decodeURIComponent function.
6229 */
6230function tryDecodeURIComponent(value) {
6231  try {
6232    return decodeURIComponent(value);
6233  } catch(e) {
6234    // Ignore any invalid uri component
6235  }
6236}
6237
6238
6239/**
6240 * Parses an escaped url query string into key-value pairs.
6241 * @returns {Object.<string,boolean|Array>}
6242 */
6243function parseKeyValue(/**string*/keyValue) {
6244  var obj = {}, key_value, key;
6245  forEach((keyValue || "").split('&'), function(keyValue) {
6246    if ( keyValue ) {
6247      key_value = keyValue.replace(/\+/g,'%20').split('=');
6248      key = tryDecodeURIComponent(key_value[0]);
6249      if ( isDefined(key) ) {
6250        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
6251        if (!hasOwnProperty.call(obj, key)) {
6252          obj[key] = val;
6253        } else if(isArray(obj[key])) {
6254          obj[key].push(val);
6255        } else {
6256          obj[key] = [obj[key],val];
6257        }
6258      }
6259    }
6260  });
6261  return obj;
6262}
6263
6264function toKeyValue(obj) {
6265  var parts = [];
6266  forEach(obj, function(value, key) {
6267    if (isArray(value)) {
6268      forEach(value, function(arrayValue) {
6269        parts.push(encodeUriQuery(key, true) +
6270                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
6271      });
6272    } else {
6273    parts.push(encodeUriQuery(key, true) +
6274               (value === true ? '' : '=' + encodeUriQuery(value, true)));
6275    }
6276  });
6277  return parts.length ? parts.join('&') : '';
6278}
6279
6280
6281/**
6282 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
6283 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
6284 * segments:
6285 *    segment       = *pchar
6286 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
6287 *    pct-encoded   = "%" HEXDIG HEXDIG
6288 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
6289 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
6290 *                     / "*" / "+" / "," / ";" / "="
6291 */
6292function encodeUriSegment(val) {
6293  return encodeUriQuery(val, true).
6294             replace(/%26/gi, '&').
6295             replace(/%3D/gi, '=').
6296             replace(/%2B/gi, '+');
6297}
6298
6299
6300/**
6301 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
6302 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
6303 * encoded per http://tools.ietf.org/html/rfc3986:
6304 *    query       = *( pchar / "/" / "?" )
6305 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
6306 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
6307 *    pct-encoded   = "%" HEXDIG HEXDIG
6308 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
6309 *                     / "*" / "+" / "," / ";" / "="
6310 */
6311function encodeUriQuery(val, pctEncodeSpaces) {
6312  return encodeURIComponent(val).
6313             replace(/%40/gi, '@').
6314             replace(/%3A/gi, ':').
6315             replace(/%24/g, '$').
6316             replace(/%2C/gi, ',').
6317             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
6318}
6319
6320
6321/**
6322 * @ngdoc directive
6323 * @name ngApp
6324 * @module ng
6325 *
6326 * @element ANY
6327 * @param {angular.Module} ngApp an optional application
6328 *   {@link angular.module module} name to load.
6329 *
6330 * @description
6331 *
6332 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
6333 * designates the **root element** of the application and is typically placed near the root element
6334 * of the page - e.g. on the `<body>` or `<html>` tags.
6335 *
6336 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngAp
6336p`
6337 * found in the document will be used to define the root element to auto-bootstrap as an
6338 * application. To run multiple applications in an HTML document you must manually bootstrap them using
6339 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
6340 *
6341 * You can specify an **AngularJS module** to be used as the root module for the application.  This
6342 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
6343 * should contain the application code needed or have dependencies on other modules that will
6344 * contain the code. See {@link angular.module} for more information.
6345 *
6346 * In the example below if the `ngApp` directive were not placed on the `html` element then the
6347 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
6348 * would not be resolved to `3`.
6349 *
6350 * `ngApp` is the easiest, and most common, way to bootstrap an application.
6351 *
6352 <example module="ngAppDemo">
6353   <file name="index.html">
6354   <div ng-controller="ngAppDemoController">
6355     I can add: {{a}} + {{b}} =  {{ a+b }}
6356   </div>
6357   </file>
6358   <file name="script.js">
6359   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
6360     $scope.a = 1;
6361     $scope.b = 2;
6362   });
6363   </file>
6364 </example>
6365 *
6366 */
6367function angularInit(element, bootstrap) {
6368  var elements = [element],
6369      appElement,
6370      module,
6371      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
6372      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
6373
6374  function append(element) {
6375    element && elements.push(element);
6376  }
6377
6378  forEach(names, function(name) {
6379    names[name] = true;
6380    append(document.getElementById(name));
6381    name = name.replace(':', '\\:');
6382    if (element.querySelectorAll) {
6383      forEach(element.querySelectorAll('.' + name), append);
6384      forEach(element.querySelectorAll('.' + name + '\\:'), append);
6385      forEach(element.querySelectorAll('[' + name + ']'), append);
6386    }
6387  });
6388
6389  forEach(elements, function(element) {
6390    if (!appElement) {
6391      var className = ' ' + element.className + ' ';
6392      var match = NG_APP_CLASS_REGEXP.exec(className);
6393      if (match) {
6394        appElement = element;
6395        module = (match[2] || '').replace(/\s+/g, ',');
6396      } else {
6397        forEach(element.attributes, function(attr) {
6398          if (!appElement && names[attr.name]) {
6399            appElement = element;
6400            module = attr.value;
6401          }
6402        });
6403      }
6404    }
6405  });
6406  if (appElement) {
6407    bootstrap(appElement, module ? [module] : []);
6408  }
6409}
6410
6411/**
6412 * @ngdoc function
6413 * @name angular.bootstrap
6414 * @module ng
6415 * @description
6416 * Use this function to manually start up angular application.
6417 *
6418 * See: {@link guide/bootstrap Bootstrap}
6419 *
6420 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
6421 * They must use {@link ng.directive:ngApp ngApp}.
6422 *
6423 * Angular will detect if it has been loaded into the browser more than once and only allow the
6424 * first loaded script to be bootstrapped and will report a warning to the browser console for
6425 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
6426 * multiple instances of Angular try to work on the DOM.
6427 *
6428 * <example name="multi-bootstrap" module="multi-bootstrap">
6429 * <file name="index.html">
6430 * <script src="../../../angular.js"></script>
6431 * <div ng-controller="BrokenTable">
6432 *   <table>
6433 *   <tr>
6434 *     <th ng-repeat="heading in headings">{{heading}}</th>
6435 *   </tr>
6436 *   <tr ng-repeat="filling in fillings">
6437 *     <td ng-repeat="fill in filling">{{fill}}</td>
6438 *   </tr>
6439 * </table>
6440 * </div>
6441 * </file>
6442 * <file name="controller.js">
6443 * var app = angular.module('multi-bootstrap', [])
6444 *
6445 * .controller('BrokenTable', function($scope) {
6446 *     $scope.headings = ['One', 'Two', 'Three'];
6447 *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
6448 * });
6449 * </file>
6450 * <file name="protractor.js" type="protractor">
6451 * it('should only insert one table cell for each item in $scope.fillings', function() {
6452 *  expect(element.all(by.css('td')).count())
6453 *      .toBe(9);
6454 * });
6455 * </file>
6456 * </example>
6457 *
6458 * @param {DOMElement} element DOM element which is the root of angular application.
6459 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
6460 *     Each item in the array should be the name of a predefined module or a (DI annotated)
6461 *     function that will be invoked by the injector as a run block.
6462 *     See: {@link angular.module modules}
6463 * @returns {auto.$injector} Returns the newly created injector for this app.
6464 */
6465function bootstrap(element, modules) {
6466  var doBootstrap = function() {
6467    element = jqLite(element);
6468
6469    if (element.injector()) {
6470      var tag = (element[0] === document) ? 'document' : startingTag(element);
6471      //Encode angle brackets to prevent input from being sanitized to empty string #8683
6472      throw ngMinErr(
6473          'btstrpd',
6474          "App Already Bootstrapped with this Element '{0}'",
6475          tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
6476    }
6477
6478    modules = modules || [];
6479    modules.unshift(['$provide', function($provide) {
6480      $provide.value('$rootElement', element);
6481    }]);
6482    modules.unshift('ng');
6483    var injector = createInjector(modules);
6484    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
6485       function(scope, element, compile, injector, animate) {
6486        scope.$apply(function() {
6487          element.data('$injector', injector);
6488          compile(element)(scope);
6489        });
6490      }]
6491    );
6492    return injector;
6493  };
6494
6495  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
6496
6497  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
6498    return doBootstrap();
6499  }
6500
6501  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
6502  angular.resumeBootstrap = function(extraModules) {
6503    forEach(extraModules, function(module) {
6504      modules.push(module);
6505    });
6506    doBootstrap();
6507  };
6508}
6509
6510var SNAKE_CASE_REGEXP = /[A-Z]/g;
6511function snake_case(name, separator) {
6512  separator = separator || '_';
6513  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
6514    return (pos ? separator : '') + letter.toLowerCase();
6515  });
6516}
6517
6518function bindJQuery() {
6519  // bind to jQuery if present;
6520  jQuery = window.jQuery;
6521  // Use jQuery if it exists with proper functionality, otherwise default to us.
6522  // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
6523  if (jQuery && jQuery.fn.on) {
6524    jqLite = jQuery;
6525    extend(jQuery.fn, {
6526      scope: JQLitePrototype.scope,
6527      isolateScope: JQLitePrototype.isolateScope,
6528      controller: JQLitePrototype.controller,
6529      injector: JQLitePrototype.injector,
6530      inheritedData: JQLitePrototype.inheritedData
6531    });
6532    // Method signature:
6533    //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
6534    jqLitePatchJQueryRemove('remove', true, true, false);
6535    jqLitePatchJQueryRemove('empty', false, false, false);
6536    jqLitePatchJQueryRemove('html', false, false, true);
6537  } else {
6538    jqLite = JQLite;
6539  }
6540  angular.element = jqLite;
6541}
6542
6543/**
6544 * throw error if the argument is falsy.
6545 */
6546function assertArg(arg, name, reason) {
6547  if (!arg) {
6548    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
6549  }
6550  return arg;
6551}
6552
6553function assertArgFn(arg, name, acceptArrayAnnotation) {
6554  if (acceptArrayAnnotation && isArray(arg)) {
6555      arg = arg[arg.length - 1];
6556  }
6557
6558  assertArg(isFunction(arg), name, 'not a function, got ' +
6559      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
6560  return arg;
6561}
6562
6563/**
6564 * throw error if the name given is hasOwnProperty
6565 * @param  {String} name    the name to test
6566 * @param  {String} context the context in which the name is used, such as module or directive
6567 */
6568function assertNotHasOwnProperty(name, context) {
6569  if (name === 'hasOwnProperty') {
6570    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
6571  }
6572}
6573
6574/**
6575 * Return the value accessible from the object by path. Any undefined traversals are ignored
6576 * @param {Object} obj starting object
6577 * @param {String} path path to traverse
6578 * @param {boolean} [bindFnToScope=true]
6579 * @returns {Object} value as accessible by path
6580 */
6581//TODO(misko): this function needs to be removed
6582function getter(obj, path, bindFnToScope) {
6583  if (!path) return obj;
6584  var keys = path.split('.');
6585  var key;
6586  var lastInstance = obj;
6587  var len = keys.length;
6588
6589  for (var i = 0; i < len; i++) {
6590    key = keys[i];
6591    if (obj) {
6592      obj = (lastInstance = obj)[key];
6593    }
6594  }
6595  if (!bindFnToScope && isFunction(obj)) {
6596    return bind(lastInstance, obj);
6597  }
6598  return obj;
6599}
6600
6601/**
6602 * Return the DOM siblings between the first and last node in the given array.
6603 * @param {Array} array like object
6604 * @returns {DOMElement}
6604 object containing the elements
6605 */
6606function getBlockElements(nodes) {
6607  var startNode = nodes[0],
6608      endNode = nodes[nodes.length - 1];
6609  if (startNode === endNode) {
6610    return jqLite(startNode);
6611  }
6612
6613  var element = startNode;
6614  var elements = [element];
6615
6616  do {
6617    element = element.nextSibling;
6618    if (!element) break;
6619    elements.push(element);
6620  } while (element !== endNode);
6621
6622  return jqLite(elements);
6623}
6624
6625/**
6626 * @ngdoc type
6627 * @name angular.Module
6628 * @module ng
6629 * @description
6630 *
6631 * Interface for configuring angular {@link angular.module modules}.
6632 */
6633
6634function setupModuleLoader(window) {
6635
6636  var $injectorMinErr = minErr('$injector');
6637  var ngMinErr = minErr('ng');
6638
6639  function ensure(obj, name, factory) {
6640    return obj[name] || (obj[name] = factory());
6641  }
6642
6643  var angular = ensure(window, 'angular', Object);
6644
6645  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
6646  angular.$$minErr = angular.$$minErr || minErr;
6647
6648  return ensure(angular, 'module', function() {
6649    /** @type {Object.<string, angular.Module>} */
6650    var modules = {};
6651
6652    /**
6653     * @ngdoc function
6654     * @name angular.module
6655     * @module ng
6656     * @description
6657     *
6658     * The `angular.module` is a global place for creating, registering and retrieving Angular
6659     * modules.
6660     * All modules (angular core or 3rd party) that should be available to an application must be
6661     * registered using this mechanism.
6662     *
6663     * When passed two or more arguments, a new module is created.  If passed only one argument, an
6664     * existing module (the name passed as the first argument to `module`) is retrieved.
6665     *
6666     *
6667     * # Module
6668     *
6669     * A module is a collection of services, directives, controllers, filters, and configuration information.
6670     * `angular.module` is used to configure the {@link auto.$injector $injector}.
6671     *
6672     * ```js
6673     * // Create a new module
6674     * var myModule = angular.module('myModule', []);
6675     *
6676     * // register a new service
6677     * myModule.value('appName', 'MyCoolApp');
6678     *
6679     * // configure existing services inside initialization blocks.
6680     * myModule.config(['$locationProvider', function($locationProvider) {
6681     *   // Configure existing providers
6682     *   $locationProvider.hashPrefix('!');
6683     * }]);
6684     * ```
6685     *
6686     * Then you can create an injector and load your modules like this:
6687     *
6688     * ```js
6689     * var injector = angular.injector(['ng', 'myModule'])
6690     * ```
6691     *
6692     * However it's more likely that you'll just use
6693     * {@link ng.directive:ngApp ngApp} or
6694     * {@link angular.bootstrap} to simplify this process for you.
6695     *
6696     * @param {!string} name The name of the module to create or retrieve.
6697     * @param {!Array.<string>=} requires If specified then new module is being created. If
6698     *        unspecified then the module is being retrieved for further configuration.
6699     * @param {Function=} configFn Optional configuration function for the module. Same as
6700     *        {@link angular.Module#config Module#config()}.
6701     * @returns {module} new module with the {@link angular.Module} api.
6702     */
6703    return function module(name, requires, configFn) {
6704      var assertNotHasOwnProperty = function(name, context) {
6705        if (name === 'hasOwnProperty') {
6706          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
6707        }
6708      };
6709
6710      assertNotHasOwnProperty(name, 'module');
6711      if (requires && modules.hasOwnProperty(name)) {
6712        modules[name] = null;
6713      }
6714      return ensure(modules, name, function() {
6715        if (!requires) {
6716          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
6717             "the module name or forgot to load it. If registering a module ensure that you " +
6718             "specify the dependencies as the second argument.", name);
6719        }
6720
6721        /** @type {!Array.<Array.<*>>} */
6722        var invokeQueue = [];
6723
6724        /** @type {!Array.<Function>} */
6725        var runBlocks = [];
6726
6727        var config = invokeLater('$injector', 'invoke');
6728
6729        /** @type {angular.Module} */
6730        var moduleInstance = {
6731          // Private state
6732          _invokeQueue: invokeQueue,
6733          _runBlocks: runBlocks,
6734
6735          /**
6736           * @ngdoc property
6737           * @name angular.Module#requires
6738           * @module ng
6739           *
6740           * @description
6741           * Holds the list of modules which the injector will load before the current module is
6742           * loaded.
6743           */
6744          requires: requires,
6745
6746          /**
6747           * @ngdoc property
6748           * @name angular.Module#name
6749           * @module ng
6750           *
6751           * @description
6752           * Name of the module.
6753           */
6754          name: name,
6755
6756
6757          /**
6758           * @ngdoc method
6759           * @name angular.Module#provider
6760           * @module ng
6761           * @param {string} name service name
6762           * @param {Function} providerType Construction function for creating new instance of the
6763           *                                service.
6764           * @description
6765           * See {@link auto.$provide#provider $provide.provider()}.
6766           */
6767          provider: invokeLater('$provide', 'provider'),
6768
6769          /**
6770           * @ngdoc method
6771           * @name angular.Module#factory
6772           * @module ng
6773           * @param {string} name service name
6774           * @param {Function} providerFunction Function for creating new instance of the service.
6775           * @description
6776           * See {@link auto.$provide#factory $provide.factory()}.
6777           */
6778          factory: invokeLater('$provide', 'factory'),
6779
6780          /**
6781           * @ngdoc method
6782           * @name angular.Module#service
6783           * @module ng
6784           * @param {string} name service name
6785           * @param {Function} constructor A constructor function that will be instantiated.
6786           * @description
6787           * See {@link auto.$provide#service $provide.service()}.
6788           */
6789          service: invokeLater('$provide', 'service'),
6790
6791          /**
6792           * @ngdoc method
6793           * @name angular.Module#value
6794           * @module ng
6795           * @param {string} name service name
6796           * @param {*} object Service instance object.
6797           * @description
6798           * See {@link auto.$provide#value $provide.value()}.
6799           */
6800          value: invokeLater('$provide', 'value'),
6801
6802          /**
6803           * @ngdoc method
6804           * @name angular.Module#constant
6805           * @module ng
6806           * @param {string} name constant name
6807           * @param {*} object Constant value.
6808           * @description
6809           * Because the constant are fixed, they get applied before other provide methods.
6810           * See {@link auto.$provide#constant $provide.constant()}.
6811           */
6812          constant: invokeLater('$provide', 'constant', 'unshift'),
6813
6814          /**
6815           * @ngdoc method
6816           * @name angular.Module#animation
6817           * @module ng
6818           * @param {string} name animation name
6819           * @param {Function} animationFactory Factory function for creating new instance of an
6820           *                                    animation.
6821           * @description
6822           *
6823           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
6824           *
6825           *
6826           * Defines an animation hook that can be later used with
6827           * {@link ngAnimate.$animate $animate} service and directives that use this service.
6828           *
6829           * ```js
6830           * module.animation('.animation-name', function($inject1, $inject2) {
6831           *   return {
6832           *     eventName : function(element, done) {
6833           *       //code to run the animation
6834           *       //once complete, then run done()
6835           *       return function cancellationFunction(element) {
6836           *         //code to cancel the animation
6837           *       }
6838           *     }
6839           *   }
6840           * })
6841           * ```
6842           *
6843           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
6844           * {@link ngAnimate ngAnimate module} for more information.
6845           */
6846          animation: invokeLater('$animateProvider', 'register'),
6847
6848          /**
6849           * @ngdoc method
6850           * @name angular.Module#filter
6851           * @module ng
6852           * @param {string} name Filter name.
6853           * @param {Function} filterFactory Factory function for creating new instance of filter.
6854           * @description
6855           * See {@link ng.$filterProvider#register $filterProvider.register()}.
6856           */
6857          filter: invokeLater('$filterProvider', 'register'),
6858
6859          /**
6860           * @ngdoc method
6861           * @name angular.Module#controller
6862           * @module ng
6863           * @param {string|Object} name Controller name, or an object map of controllers where the
6864           *    keys are the names and the values are the constructors.
6865           * @param {Function} constructor Controller constructor function.
6866           * @description
6867           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
6868           */
6869          controller: invokeLater('$controllerProvider', 'register'),
6870
6871          /**
6872           * @ngdoc method
6873           * @name angular.Module#directive
6874           * @module ng
6875           * @param {string|Object} name Directive name, or an object map of directives where the
6876           *    keys are the names and the values are the factories.
6877           * @param {Function} directiveFactory Factory function for creating new instance of
6878           * directives.
6879           * @description
6880           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
6881           */
6882          directive: invokeLater('$compileProvider', 'directive'),
6883
6884          /**
6885           * @ngdoc method
6886           * @name angular.Module#config
6887           * @module ng
6888           * @param {Function} configFn Execute this function on module load. Useful for service
6889           *    configuration.
6890           * @description
6891           * Use this method to register work which needs to be performed on module loading.
6892           * For more about how to configure services, see
6893           * {@link providers#providers_provider-recipe Provider Recipe}.
6894           */
6895          config: config,
6896
6897          /**
6898           * @ngdoc method
6899           * @name angular.Module#run
6900           * @module ng
6901           * @param {Function} initializationFn Execute this function after injector creation.
6902           *    Useful for application initialization.
6903           * @description
6904           * Use this method to register work which should be performed when the injector is done
6905           * loading all modules.
6906           */
6907          run: function(block) {
6908            runBlocks.push(block);
6909            return this;
6910          }
6911        };
6912
6913        if (configFn) {
6914          config(configFn);
6915        }
6916
6917        return  moduleInstance;
6918
6919        /**
6920         * @param {string} provider
6921         * @param {string} method
6922         * @param {String=} insertMethod
6923         * @returns {angular.Module}
6924         */
6925        function invokeLater(provider, method, insertMethod) {
6926          return function() {
6927            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
6928            return moduleInstance;
6929          };
6930        }
6931      });
6932    };
6933  });
6934
6935}
6936
6937/* global angularModule: true,
6938  version: true,
6939
6940  $LocaleProvider,
6941  $CompileProvider,
6942
6943    htmlAnchorDirective,
6944    inputDirective,
6945    inputDirective,
6946    formDirective,
6947    scriptDirective,
6948    selectDirective,
6949    styleDirective,
6950    optionDirective,
6951    ngBindDirective,
6952    ngBindHtmlDirective,
6953    ngBindTemplateDirective,
6954    ngClassDirective,
6955    ngClassEvenDirective,
6956    ngClassOddDirective,
6957    ngCspDirective,
6958    ngCloakDirective,
6959    ngControllerDirective,
6960    ngFormDirective,
6961    ngHideDirective,
6962    ngIfDirective,
6963    ngIncludeDirective,
6964    ngIncludeFillContentDirective,
6965    ngInitDirective,
6966    ngNonBindableDirective,
6967    ngPluralizeDirective,
6968    ngRepeatDirective,
6969    ngShowDirective,
6970    ngStyleDirective,
6971    ngSwitchDirective,
6972    ngSwitchWhenDirective,
6973    ngSwitchDefaultDirective,
6974    ngOptionsDirective,
6975    ngTranscludeDirective,
6976    ngModelDirective,
6977    ngListDirective,
6978    ngChangeDirective,
6979    requiredDirective,
6980    requiredDirective,
6981    ngValueDirective,
6982    ngAttributeAliasDirectives,
6983    ngEventDirectives,
6984
6985    $AnchorScrollProvider,
6986    $AnimateProvider,
6987    $BrowserProvider,
6988    $CacheFactoryProvider,
6989    $ControllerProvider,
6990    $DocumentProvider,
6991    $ExceptionHandlerProvider,
6992    $FilterProvider,
6993    $InterpolateProvider,
6994    $IntervalProvider,
6995    $HttpProvider,
6996    $HttpBackendProvider,
6997    $LocationProvider,
6998    $LogProvider,
6999    $ParseProvider,
7000    $RootScopeProvider,
7001    $QProvider,
7002    $$SanitizeUriProvider,
7003    $SceProvider,
7004    $SceDelegateProvider,
7005    $SnifferProvider,
7006    $TemplateCacheProvider,
7007    $TimeoutProvider,
7008    $$RAFProvider,
7009    $$AsyncCallbackProvider,
7010    $WindowProvider
7011*/
7012
7013
7014/**
7015 * @ngdoc object
7016 * @name angular.version
7017 * @module ng
7018 * @description
7019 * An object that contains information about the current AngularJS version. This object has the
7020 * following properties:
7021 *
7022 * - `full` – `{string}` – Full version string, such as "0.9.18".
7023 * - `major` – `{number}` – Major version number, such as "0".
7024 * - `minor` – `{number}` – Minor version number, such as "9".
7025 * - `dot` – `{number}` – Dot version number, such as "18".
7026 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
7027 */
7028var version = {
7029  full: '1.2.25',    // all of these placeholder strings will be replaced by grunt's
7030  major: 1,    // package task
7031  minor: 2,
7032  dot: 25,
7033  codeName: 'hypnotic-gesticulation'
7034};
7035
7036
7037function publishExternalAPI(angular){
7038  extend(angular, {
7039    'bootstrap': bootstrap,
7040    'copy': copy,
7041    'extend': extend,
7042    'equals': equals,
7043    'element': jqLite,
7044    'forEach': forEach,
7045    'injector': createInjector,
7046    'noop': noop,
7047    'bind': bind,
7048    'toJson': toJson,
7049    'fromJson': fromJson,
7050    'identity': identity,
7051    'isUndefined': isUndefined,
7052    'isDefined': isDefined,
7053    'isString': isString,
7054    'isFunction': isFunction,
7055    'isObject': isObject,
7056    'isNumber': isNumber,
7057    'isElement': isElement,
7058    'isArray': isArray,
7059    'version': version,
7060    'isDate': isDate,
7061    'lowercase': lowercase,
7062    'uppercase': uppercase,
7063    'callbacks': {counter: 0},
7064    '$$minErr': minErr,
7065    '$$csp': csp
7066  });
7067
7068  angularModule = setupModuleLoader(window);
7069  try {
7070    angularModule('ngLocale');
7071  } catch (e) {
7072    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
7073  }
7074
7075  angularModule('ng', ['ngLocale'], ['$provide',
7076    function ngModule($provide) {
7077      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
7078      $provide.provider({
7079        $$sanitizeUri: $$SanitizeUriProvider
7080      });
7081      $provide.provider('$compile', $CompileProvider).
7082        directive({
7083            a: htmlAnchorDirective,
7084            input: inputDirective,
7085            textarea: inputDirective,
7086            form: formDirective,
7087            script: scriptDirective,
7088            select: selectDirective,
7089            style: styleDirective,
7090            option: optionDirective,
7091            ngBind: ngBindDirective,
7092            ngBindHtml: ngBindHtmlDirective,
7093            ngBindTemplate: ngBindTemplateDirective,
7094            ngClass: ngClassDirective,
7095            ngClassEven: ngClassEvenDirective,
7096            ngClassOdd: ngClassOddDirective,
7097            ngCloak: ngCloakDirective,
7098            ngController: ngControllerDirective,
7099            ngForm: ngFormDirective,
7100            ngHide: ngHideDirective,
7101            ngIf: ngIfDirective,
7102            ngInclude: ngIncludeDirective,
7103            ngInit: ngInitDirective,
7104            ngNonBindable: ngNonBindableDirective,
7105            ngPluralize: ngPluralizeDirective,
7106            ngRepeat: ngRepeatDirective,
7107            ngShow: ngShowDirective,
7108            ngStyle: ngStyleDirective,
7109            ngSwitch: ngSwitchDirective,
7110            ngSwitchWhen: ngSwitchWhenDirective,
7111            ngSwitchDefault: ngSwitchDefaultDirective,
7112            ngOptions: ngOptionsDirective,
7113            ngTransclude: ngTranscludeDirective,
7114            ngModel: ngModelDirective,
7115            ngList: ngListDirective,
7116            ngChange: ngChangeDirective,
7117            required: requiredDirective,
7118            ngRequired: requiredDirective,
7119            ngValue: ngValueDirective
7120        }).
7121        directive({
7122          ngInclude: ngIncludeFillContentDirective
7123        }).
7124        directive(ngAttributeAliasDirectives).
7125        directive(ngEventDirectives);
7126      $provide.provider({
7127        $anchorScroll: $AnchorScrollProvider,
7128        $animate: $AnimateProvider,
7129        $browser: $BrowserProvider,
7130        $cacheFactory: $CacheFactoryProvider,
7131        $controller: $ControllerProvider,
7132        $document: $DocumentProvider,
7133        $exceptionHandler: $ExceptionHandlerProvider,
7134        $filter: $FilterProvider,
7135        $interpolate: $InterpolateProvider,
7136        $interval: $IntervalProvider,
7137        $http: $HttpProvider,
7138        $httpBackend: $HttpBackendProvider,
7139        $location: $LocationProvider,
7140        $log: $LogProvider,
7141        $parse: $ParseProvider,
7142        $rootScope: $RootScopeProvider,
7143        $q: $QProvider,
7144        $sce: $SceProvider,
7145        $sceDelegate: $SceDelegateProvider,
7146        $sniffer: $SnifferProvider,
7147        $templateCache: $TemplateCacheProvider,
7148        $timeout: $TimeoutProvider,
7149        $window: $WindowProvider,
7150        $$rAF: $$RAFProvider,
7151        $$asyncCallback : $$AsyncCallbackProvider
7152      });
7153    }
7154  ]);
7155}
7156
7157/* global JQLitePrototype: true,
7158  addEventListenerFn: true,
7159  removeEventListenerFn: true,
7160  BOOLEAN_ATTR: true
7161*/
7162
7163//////////////////////////////////
7164//JQLite
7165//////////////////////////////////
7166
7167/**
7168 * @ngdoc function
7169 * @name angular.element
7170 * @module ng
7171 * @kind function
7172 *
7173 * @description
7174 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
7175 *
7176 * If jQuery is available, `angular.element` is an alias for the
7177 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
7178 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
7179 *
7180 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
7181 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
7182 * commonly needed functionality with the goal of having a very small footprint.</div>
7183 *
7184 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
7185 *
7186 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
7187 * jqLite; they are never raw DOM references.</div>
7188 *
7189 * ## Angular's jqLite
7190 * jqLite provides only the following jQuery methods:
7191 *
7192 * - [`addClass()`](http://api.jquery.com/addClass/)
7193 * - [`after()`](http://api.jquery.com/after/)
7194 * - [`append()`](http://api.jquery.com/append/)
7195 * - [`attr()`](http://api.jquery.com/attr/)
7196 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
7197 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
7198 * - [`clone()`](http://api.jquery.com/clone/)
7199 * - [`contents()`](http://api.jquery.com/contents/)
7200 * - [`css()`](http://api.jquery.com/css/)
7201 * - [`data()`](http://api.jquery.com/data/)
7202 * - [`empty()`](http://api.jquery.com/empty/)
7203 * - [`eq()`](http://api.jquery.com/eq/)
7204 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
7205 * - [`hasClass()`](http://api.jquery.com/hasClass/)
7206 * - [`html()`](http://api.jquery.com/html/)
7207 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
7208 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
7209 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
7210 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
7211 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
7212 * - [`prepend()`](http://api.jquery.com/prepend/)
7213 * - [`prop()`](http://api.jquery.com/prop/)
7214 * - [`ready()`](http://api.jquery.com/ready/)
7215 * - [`remove()`](http://api.jquery.com/remove/)
7216 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
7217 * - [`removeClass()`](http://api.jquery.com/removeClass/)
7218 * - [`removeData()`](http://api.jquery.com/removeData/)
7219 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
7220 * - [`text()`](http://api.jquery.com/text/)
7221 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
7222 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
7223 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
7224 * - [`val()`](http://api.jquery.com/val/)
7225 * - [`wrap()`](http://api.jquery.com/wrap/)
7226 *
7227 * ## jQuery/jqLite Extras
7228 * Angular also provides the following additional methods and events to both jQuery and jqLite:
7229 *
7230 * ### Events
7231 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction a
7231pis and fires this event
7232 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
7233 *    element before it is removed.
7234 *
7235 * ### Methods
7236 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
7237 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
7238 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
7239 *   `'ngModel'`).
7240 * - `injector()` - retrieves the injector of the current element or its parent.
7241 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
7242 *   element or its parent.
7243 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
7244 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
7245 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
7246 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
7247 *   parent element is reached.
7248 *
7249 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
7250 * @returns {Object} jQuery object.
7251 */
7252
7253JQLite.expando = 'ng339';
7254
7255var jqCache = JQLite.cache = {},
7256    jqId = 1,
7257    addEventListenerFn = (window.document.addEventListener
7258      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
7259      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
7260    removeEventListenerFn = (window.document.removeEventListener
7261      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
7262      : function(element, type, fn) {element.detachEvent('on' + type, fn); });
7263
7264/*
7265 * !!! This is an undocumented "private" function !!!
7266 */
7267var jqData = JQLite._data = function(node) {
7268  //jQuery always returns an object on cache miss
7269  return this.cache[node[this.expando]] || {};
7270};
7271
7272function jqNextId() { return ++jqId; }
7273
7274
7275var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
7276var MOZ_HACK_REGEXP = /^moz([A-Z])/;
7277var jqLiteMinErr = minErr('jqLite');
7278
7279/**
7280 * Converts snake_case to camelCase.
7281 * Also there is special case for Moz prefix starting with upper case letter.
7282 * @param name Name to normalize
7283 */
7284function camelCase(name) {
7285  return name.
7286    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
7287      return offset ? letter.toUpperCase() : letter;
7288    }).
7289    replace(MOZ_HACK_REGEXP, 'Moz$1');
7290}
7291
7292/////////////////////////////////////////////
7293// jQuery mutation patch
7294//
7295// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
7296// $destroy event on all DOM nodes being removed.
7297//
7298/////////////////////////////////////////////
7299
7300function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
7301  var originalJqFn = jQuery.fn[name];
7302  originalJqFn = originalJqFn.$original || originalJqFn;
7303  removePatch.$original = originalJqFn;
7304  jQuery.fn[name] = removePatch;
7305
7306  function removePatch(param) {
7307    // jshint -W040
7308    var list = filterElems && param ? [this.filter(param)] : [this],
7309        fireEvent = dispatchThis,
7310        set, setIndex, setLength,
7311        element, childIndex, childLength, children;
7312
7313    if (!getterIfNoArguments || param != null) {
7314      while(list.length) {
7315        set = list.shift();
7316        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
7317          element = jqLite(set[setIndex]);
7318          if (fireEvent) {
7319            element.triggerHandler('$destroy');
7320          } else {
7321            fireEvent = !fireEvent;
7322          }
7323          for(childIndex = 0, childLength = (children = element.children()).length;
7324              childIndex < childLength;
7325              childIndex++) {
7326            list.push(jQuery(children[childIndex]));
7327          }
7328        }
7329      }
7330    }
7331    return originalJqFn.apply(this, arguments);
7332  }
7333}
7334
7335var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
7336var HTML_REGEXP = /<|&#?\w+;/;
7337var TAG_NAME_REGEXP = /<([\w:]+)/;
7338var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
7339
7340var wrapMap = {
7341  'option': [1, '<select multiple="multiple">', '</select>'],
7342
7343  'thead': [1, '<table>', '</table>'],
7344  'col': [2, '<table><colgroup>', '</colgroup></table>'],
7345  'tr': [2, '<table><tbody>', '</tbody></table>'],
7346  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
7347  '_default': [0, "", ""]
7348};
7349
7350wrapMap.optgroup = wrapMap.option;
7351wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
7352wrapMap.th = wrapMap.td;
7353
7354function jqLiteIsTextNode(html) {
7355  return !HTML_REGEXP.test(html);
7356}
7357
7358function jqLiteBuildFragment(html, context) {
7359  var elem, tmp, tag, wrap,
7360      fragment = context.createDocumentFragment(),
7361      nodes = [], i, j, jj;
7362
7363  if (jqLiteIsTextNode(html)) {
7364    // Convert non-html into a text node
7365    nodes.push(context.createTextNode(html));
7366  } else {
7367    tmp = fragment.appendChild(context.createElement('div'));
7368    // Convert html into DOM nodes
7369    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
7370    wrap = wrapMap[tag] || wrapMap._default;
7371    tmp.innerHTML = '<div>&#160;</div>' +
7372      wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
7373    tmp.removeChild(tmp.firstChild);
7374
7375    // Descend through wrappers to the right content
7376    i = wrap[0];
7377    while (i--) {
7378      tmp = tmp.lastChild;
7379    }
7380
7381    for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);
7382
7383    tmp = fragment.firstChild;
7384    tmp.textContent = "";
7385  }
7386
7387  // Remove wrapper from fragment
7388  fragment.textContent = "";
7389  fragment.innerHTML = ""; // Clear inner HTML
7390  return nodes;
7391}
7392
7393function jqLiteParseHTML(html, context) {
7394  context = context || document;
7395  var parsed;
7396
7397  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
7398    return [context.createElement(parsed[1])];
7399  }
7400
7401  return jqLiteBuildFragment(html, context);
7402}
7403
7404/////////////////////////////////////////////
7405function JQLite(element) {
7406  if (element instanceof JQLite) {
7407    return element;
7408  }
7409  if (isString(element)) {
7410    element = trim(element);
7411  }
7412  if (!(this instanceof JQLite)) {
7413    if (isString(element) && element.charAt(0) != '<') {
7414      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
7415    }
7416    return new JQLite(element);
7417  }
7418
7419  if (isString(element)) {
7420    jqLiteAddNodes(this, jqLiteParseHTML(element));
7421    var fragment = jqLite(document.createDocumentFragment());
7422    fragment.append(this);
7423  } else {
7424    jqLiteAddNodes(this, element);
7425  }
7426}
7427
7428function jqLiteClone(element) {
7429  return element.cloneNode(true);
7430}
7431
7432function jqLiteDealoc(element){
7433  jqLiteRemoveData(element);
7434  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
7435    jqLiteDealoc(children[i]);
7436  }
7437}
7438
7439function jqLiteOff(element, type, fn, unsupported) {
7440  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
7441
7442  var events = jqLiteExpandoStore(element, 'events'),
7443      handle = jqLiteExpandoStore(element, 'handle');
7444
7445  if (!handle) return; //no listeners registered
7446
7447  if (isUndefined(type)) {
7448    forEach(events, function(eventHandler, type) {
7449      removeEventListenerFn(element, type, eventHandler);
7450      delete events[type];
7451    });
7452  } else {
7453    forEach(type.split(' '), function(type) {
7454      if (isUndefined(fn)) {
7455        removeEventListenerFn(element, type, events[type]);
7456        delete events[type];
7457      } else {
7458        arrayRemove(events[type] || [], fn);
7459      }
7460    });
7461  }
7462}
7463
7464function jqLiteRemoveData(element, name) {
7465  var expandoId = element.ng339,
7466      expandoStore = jqCache[expandoId];
7467
7468  if (expandoStore) {
7469    if (name) {
7470      delete jqCache[expandoId].data[name];
7471      return;
7472    }
7473
7474    if (expandoStore.handle) {
7475      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
7476      jqLiteOff(element);
7477    }
7478    delete jqCache[expandoId];
7479    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
7480  }
7481}
7482
7483function jqLiteExpandoStore(element, key, value) {
7484  var expandoId = element.ng339,
7485      expandoStore = jqCache[expandoId || -1];
7486
7487  if (isDefined(value)) {
7488    if (!expandoStore) {
7489      element.ng339 = expandoId = jqNextId();
7490      expandoStore = jqCache[expandoId] = {};
7491    }
7492    expandoStore[key] = value;
7493  } else {
7494    return expandoStore && expandoStore[key];
7495  }
7496}
7497
7498function jqLiteData(element, key, value) {
7499  var data = jqLiteExpandoStore(element, 'data'),
7500      isSetter = isDefined(value),
7501      keyDefined = !isSetter && isDefined(key),
7502      isSimpleGetter = keyDefined && !isObject(key);
7503
7504  if (!data && !isSimpleGetter) {
7505    jqLiteExpandoStore(element, 'data', data = {});
7506  }
7507
7508  if (isSetter) {
7509    data[key] = value;
7510  } else {
7511    if (keyDefined) {
7512      if (isSimpleGetter) {
7513        // don't create data in this case.
7514        return data && data[key];
7515      } else {
7516        extend(data, key);
7517      }
7518    } else {
7519      return data;
7520    }
7521  }
7522}
7523
7524function jqLiteHasClass(element, selector) {
7525  if (!element.getAttribute) return false;
7526  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
7527      indexOf( " " + selector + " " ) > -1);
7528}
7529
7530function jqLiteRemoveClass(element, cssClasses) {
7531  if (cssClasses && element.setAttribute) {
7532    forEach(cssClasses.split(' '), function(cssClass) {
7533      element.setAttribute('class', trim(
7534          (" " + (element.getAttribute('class') || '') + " ")
7535          .replace(/[\n\t]/g, " ")
7536          .replace(" " + trim(cssClass) + " ", " "))
7537      );
7538    });
7539  }
7540}
7541
7542function jqLiteAddClass(element, cssClasses) {
7543  if (cssClasses && element.setAttribute) {
7544    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
7545                            .replace(/[\n\t]/g, " ");
7546
7547    forEach(cssClasses.split(' '), function(cssClass) {
7548      cssClass = trim(cssClass);
7549      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
7550        existingClasses += cssClass + ' ';
7551      }
7552    });
7553
7554    element.setAttribute('class', trim(existingClasses));
7555  }
7556}
7557
7558function jqLiteAddNodes(root, elements) {
7559  if (elements) {
7560    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
7561      ? elements
7562      : [ elements ];
7563    for(var i=0; i < elements.length; i++) {
7564      root.push(elements[i]);
7565    }
7566  }
7567}
7568
7569function jqLiteController(element, name) {
7570  return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
7571}
7572
7573function jqLiteInheritedData(element, name, value) {
7574  // if element is the document object work with the html element instead
7575  // this makes $(document).scope() possible
7576  if(element.nodeType == 9) {
7577    element = element.documentElement;
7578  }
7579  var names = isArray(name) ? name : [name];
7580
7581  while (element) {
7582    for (var i = 0, ii = names.length; i < ii; i++) {
7583      if ((value = jqLite.data(element, names[i])) !== undefined) return value;
7584    }
7585
7586    // If dealing with a document fragment node with a host element, and no parent, use the host
7587    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
7588    // to lookup parent controllers.
7589    element = element.parentNode || (element.nodeType === 11 && element.host);
7590  }
7591}
7592
7593function jqLiteEmpty(element) {
7594  for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
7595    jqLiteDealoc(childNodes[i]);
7596  }
7597  while (element.firstChild) {
7598    element.removeChild(element.firstChild);
7599  }
7600}
7601
7602//////////////////////////////////////////
7603// Functions which are declared directly.
7604//////////////////////////////////////////
7605var JQLitePrototype = JQLite.prototype = {
7606  ready: function(fn) {
7607    var fired = false;
7608
7609    function trigger() {
7610      if (fired) return;
7611      fired = true;
7612      fn();
7613    }
7614
7615    // check if document already is loaded
7616    if (document.readyState === 'complete'){
7617      setTimeout(trigger);
7618    } else {
7619      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
7620      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
7621      // jshint -W064
7622      JQLite(window).on('load', trigger); // fallback to window.onload for others
7623      // jshint +W064
7624    }
7625  },
7626  toString: function() {
7627    var value = [];
7628    forEach(this, function(e){ value.push('' + e);});
7629    return '[' + value.join(', ') + ']';
7630  },
7631
7632  eq: function(index) {
7633      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
7634  },
7635
7636  length: 0,
7637  push: push,
7638  sort: [].sort,
7639  splice: [].splice
7640};
7641
7642//////////////////////////////////////////
7643// Functions iterating getter/setters.
7644// these functions return self on setter and
7645// value on get.
7646//////////////////////////////////////////
7647var BOOLEAN_ATTR = {};
7648forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
7649  BOOLEAN_ATTR[lowercase(value)] = value;
7650});
7651var BOOLEAN_ELEMENTS = {};
7652forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
7653  BOOLEAN_ELEMENTS[uppercase(value)] = true;
7654});
7655
7656function getBooleanAttrName(element, name) {
7657  // check dom last since we will most likely fail on name
7658  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
7659
7660  // booleanAttr is here twice to minimize DOM access
7661  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
7662}
7663
7664forEach({
7665  data: jqLiteData,
7666  removeData: jqLiteRemoveData
7667}, function(fn, name) {
7668  JQLite[name] = fn;
7669});
7670
7671forEach({
7672  data: jqLiteData,
7673  inheritedData: jqLiteInheritedData,
7674
7675  scope: function(element) {
7676    // Can't use jqLiteData here directly so we stay compatible with jQuery!
7677    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
7678  },
7679
7680  isolateScope: function(element) {
7681    // Can't use jqLiteData here directly so we stay compatible with jQuery!
7682    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
7683  },
7684
7685  controller: jqLiteController,
7686
7687  injector: function(element) {
7688    return jqLiteInheritedData(element, '$injector');
7689  },
7690
7691  removeAttr: function(element,name) {
7692    element.removeAttribute(name);
7693  },
7694
7695  hasClass: jqLiteHasClass,
7696
7697  css: function(element, name, value) {
7698    name = camelCase(name);
7699
7700    if (isDefined(value)) {
7701      element.style[name] = value;
7702    } else {
7703      var val;
7704
7705      if (msie <= 8) {
7706        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
7707        val = element.currentStyle && element.currentStyle[name];
7708        if (val === '') val = 'auto';
7709      }
7710
7711      val = val || element.style[name];
7712
7713      if (msie <= 8) {
7714        // jquery weirdness :-/
7715        val = (val === '') ? undefined : val;
7716      }
7717
7718      return  val;
7719    }
7720  },
7721
7722  attr: function(element, name, value){
7723    var lowercasedName = lowercase(name);
7724    if (BOOLEAN_ATTR[lowercasedName]) {
7725      if (isDefined(value)) {
7726        if (!!value) {
7727          element[name] = true;
7728          element.setAttribute(name, lowercasedName);
7729        } else {
7730          element[name] = false;
7731          element.removeAttribute(lowercasedName);
7732        }
7733      } else {
7734        return (element[name] ||
7735                 (element.attributes.getNamedItem(name)|| noop).specified)
7736               ? lowercasedName
7737               : undefined;
7738      }
7739    } else if (isDefined(value)) {
7740      element.setAttribute(name, value);
7741    } else if (element.getAttribute) {
7742      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
7743      // some elements (e.g. Document) don't have get attribute, so return undefined
7744      var ret = element.getAttribute(name, 2);
7745      // normalize non-existing attributes to undefined (as jQuery)
7746      return ret === null ? undefined : ret;
7747    }
7748  },
7749
7750  prop: function(element, name, value) {
7751    if (isDefined(value)) {
7752      element[name] = value;
7753    } else {
7754      return element[name];
7755    }
7756  },
7757
7758  text: (function() {
7759    var NODE_TYPE_TEXT_PROPERTY = [];
7760    if (msie < 9) {
7761      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
7762      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
7763    } else {
7764      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
7765      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
7766    }
7767    getText.$dv = '';
7768    return getText;
7769
7770    function getText(element, value) {
7771      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
7772      if (isUndefined(value)) {
7773        return textProp ? element[textProp] : '';
7774      }
7775      element[textProp] = value;
7776    }
7777  })(),
7778
7779  val: function(element, value) {
7780    if (isUndefined(value)) {
7781      if (nodeName_(element) === 'SELECT' && element.multiple) {
7782        var result = [];
7783        forEach(element.options, function (option) {
7784          if (option.selected) {
7785            result.push(option.value || option.text);
7786          }
7787        });
7788        return result.length === 0 ? null : result;
7789      }
7790      return element.value;
7791    }
7792    element.value = value;
7793  },
7794
7795  html: function(element, value) {
7796    if (isUndefined(value)) {
7797      return element.innerHTML;
7798    }
7799    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
7800      jqLiteDealoc(childNodes[i]);
7801    }
7802    element.innerHTML = value;
7803  },
7804
7805  empty: jqLiteEmpty
7806}, function(fn, name){
7807  /**
7808   * Properties: writes return selection, reads return first value
7809   */
7810  JQLite.prototype[name] = function(arg1, arg2) {
7811    var i, key;
7812    var nodeCount = this.length;
7813
7814    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
7815    // in a way that survives minification.
7816    // jqLiteEmpty takes no arguments but is a setter.
7817    if (fn !== jqLiteEmpty &&
7818        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
7819      if (isObject(arg1)) {
7820
7821        // we are a write, but the object properties are the key/values
7822        for (i = 0; i < nodeCount; i++) {
7823          if (fn === jqLiteData) {
7824            // data() takes the whole object in jQuery
7825            fn(this[i], arg1);
7826          } else {
7827            for (key in arg1) {
7828              fn(this[i], key, arg1[key]);
7829            }
7830          }
7831        }
7832        // return self for chaining
7833        return this;
7834      } else {
7835        // we are a read, so read the first child.
7836        // TODO: do we still need this?
7837        var value = fn.$dv;
7838        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
7839        var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
7840        for (var j = 0; j < jj; j++) {
7841          var nodeValue = fn(this[j], arg1, arg2);
7842          value = value ? value + nodeValue : nodeValue;
7843        }
7844        return value;
7845      }
7846    } else {
7847      // we are a write, so apply to all children
7848      for (i = 0; i < nodeCount; i++) {
7849        fn(this[i], arg1, arg2);
7850      }
7851      // return self for chaining
7852      return this;
7853    }
7854  };
7855});
7856
7857function createEventHandler(element, events) {
7858  var eventHandler = function (event, type) {
7859    if (!event.preventDefault) {
7860      event.preventDefault = function() {
7861        event.returnValue = false; //ie
7862      };
7863    }
7864
7865    if (!event.stopPropagation) {
7866      event.stopPropagation = function() {
7867        event.cancelBubble = true; //ie
7868      };
7869    }
7870
7871    if (!event.target) {
7872      event.target = event.srcElement || document;
7873    }
7874
7875    if (isUndefined(event.defaultPrevented)) {
7876      var prevent = event.preventDefault;
7877      event.preventDefault = function() {
7878        event.defaultPrevented = true;
7879        prevent.call(event);
7880      };
7881      event.defaultPrevented = false;
7882    }
7883
7884    event.isDefaultPrevented = function() {
7885      return event.defaultPrevented || event.returnValue === false;
7886    };
7887
7888    // Copy event handlers in case event handlers array is modified during execution.
7889    var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
7890
7891    forEach(eventHandlersCopy, function(fn) {
7892      fn.call(element, event);
7893    });
7894
7895    // Remove monkey-patched methods (IE),
7896    // as they would cause memory leaks in IE8.
7897    if (msie <= 8) {
7898      // IE7/8 does not allow to delete property on native object
7899      event.preventDefault = null;
7900      event.stopPropagation = null;
7901      event.isDefaultPrevented = null;
7902    } else {
7903      // It shouldn't affect normal browsers (native methods are defined on prototype).
7904      delete event.preventDefault;
7905      delete event.stopPropagation;
7906      delete event.isDefaultPrevented;
7907    }
7908  };
7909  eventHandler.elem = element;
7910  return eventHandler;
7911}
7912
7913//////////////////////////////////////////
7914// Functions iterating traversal.
7915// These functions chain results into a single
7916// selector.
7917//////////////////////////////////////////
7918forEach({
7919  removeData: jqLiteRemoveData,
7920
7921  dealoc: jqLiteDealoc,
7922
7923  on: function onFn(element, type, fn, unsupported){
7924    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
7925
7926    var events = jqLiteExpandoStore(element, 'events'),
7927        handle = jqLiteExpandoStore(element, 'handle');
7928
7929    if (!events) jqLiteExpandoStore(element, 'events', events = {});
7930    if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
7931
7932    forEach(type.split(' '), function(type){
7933      var eventFns = events[type];
7934
7935      if (!eventFns) {
7936        if (type == 'mouseenter' || type == 'mouseleave') {
7937          var contains = document.body.contains || document.body.compareDocumentPosition ?
7938          function( a, b ) {
7939            // jshint bitwise: false
7940            var adown = a.nodeType === 9 ? a.documentElement : a,
7941            bup = b && b.parentNode;
7942            return a === bup || !!( bup && bup.nodeType === 1 && (
7943              adown.contains ?
7944              adown.contains( bup ) :
7945              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
7946              ));
7947            } :
7948            function( a, b ) {
7949              if ( b ) {
7950                while ( (b = b.parentNode) ) {
7951                  if ( b === a ) {
7952                    return true;
7953                  }
7954                }
7955              }
7956              return false;
7957            };
7958
7959          events[type] = [];
7960
7961          // Refer to jQuery's implementation of mouseenter & mouseleave
7962          // Read about mouseenter and mouseleave:
7963          // http://www.quirksmode.org/js/events_mouse.html#link8
7964          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
7965
7966          onFn(element, eventmap[type], function(event) {
7967            var target = this, related = event.relatedTarget;
7968            // For mousenter/leave call the handler if related is outside the target.
7969            // NB: No relatedTarget if the mouse left/entered the browser window
7970            if ( !related || (related !== target && !contains(target, related)) ){
7971              handle(event, type);
7972            }
7973          });
7974
7975        } else {
7976          addEventListenerFn(element, type, handle);
7977          events[type] = [];
7978        }
7979        eventFns = events[type];
7980      }
7981      eventFns.push(fn);
7982    });
7983  },
7984
7985  off: jqLiteOff,
7986
7987  one: function(element, type, fn) {
7988    element = jqLite(element);
7989
7990    //add the listener twice so that when it is called
7991    //you can remove the original function and still be
7992    //able to call element.off(ev, fn) normally
7993    element.on(type, function onFn() {
7994      element.off(type, fn);
7995      element.off(type, onFn);
7996    });
7997    element.on(type, fn);
7998  },
7999
8000  replaceWith: function(element, replaceNode) {
8001    var index, parent = element.parentNode;
8002    jqLiteDealoc(element);
8003    forEach(new JQLite(replaceNode), function(node){
8004      if (index) {
8005        parent.insertBefore(node, index.nextSibling);
8006      } else {
8007        parent.replaceChild(node, element);
8008      }
8009      index = node;
8010    });
8011  },
8012
8013  children: function(element) {
8014    var children = [];
8015    forEach(element.childNodes, function(element){
8016      if (element.nodeType === 1)
8017        children.push(element);
8018    });
8019    return children;
8020  },
8021
8022  contents: function(element) {
8023    return element.contentDocument || element.childNodes || [];
8024  },
8025
8026  append: function(element, node) {
8027    forEach(new JQLite(node), function(child){
8028      if (element.nodeType === 1 || element.nodeType === 11) {
8029        element.appendChild(child);
8030      }
8031    });
8032  },
8033
8034  prepend: function(element, node) {
8035    if (element.nodeType === 1) {
8036      var index = element.firstChild;
8037      forEach(new JQLite(node), function(child){
8038        element.insertBefore(child, index);
8039      });
8040    }
8041  },
8042
8043  wrap: function(element, wrapNode) {
8044    wrapNode = jqLite(wrapNode)[0];
8045    var parent = element.parentNode;
8046    if (parent) {
8047      parent.replaceChild(wrapNode, element);
8048    }
8049    wrapNode.appendChild(element);
8050  },
8051
8052  remove: function(element) {
8053    jqLiteDealoc(element);
8054    var parent = element.parentNode;
8055    if (parent) parent.removeChild(element);
8056  },
8057
8058  after: function(element, newElement) {
8059    var index = element, parent = element.parentNode;
8060    forEach(new JQLite(newElement), function(node){
8061      parent.insertBefore(node, index.nextSibling);
8062      index = node;
8063    });
8064  },
8065
8066  addClass: jqLiteAddClass,
8067  removeClass: jqLiteRemoveClass,
8068
8069  toggleClass: function(element, selector, condition) {
8070    if (selector) {
8071      forEach(selector.split(' '), function(className){
8072        var classCondition = condition;
8073        if (isUndefined(classCondition)) {
8074          classCondition = !jqLiteHasClass(element, className);
8075        }
8076        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
8077      });
8078    }
8079  },
8080
8081  parent: function(element) {
8082    var parent = element.parentNode;
8083    return parent && parent.nodeType !== 11 ? parent : null;
8084  },
8085
8086  next: function(element) {
8087    if (element.nextElementSibling) {
8088      return element.nextElementSibling;
8089    }
8090
8091    // IE8 doesn't have nextElementSibling
8092    var elm = element.nextSibling;
8093    while (elm != null && elm.nodeType !== 1) {
8094      elm = elm.nextSibling;
8095    }
8096    return elm;
8097  },
8098
8099  find: function(element, selector) {
8100    if (element.getElementsByTagName) {
8101      return element.getElementsByTagName(selector);
8102    } else {
8103      return [];
8104    }
8105  },
8106
8107  clone: jqLiteClone,
8108
8109  triggerHandler: function(element, event, extraParameters) {
8110
8111    var dummyEvent, eventFnsCopy, handlerArgs;
8112    var eventName = event.type || event;
8113    var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
8114
8115    if (eventFns) {
8116
8117      // Create a dummy event to pass to the handlers
8118      dummyEvent = {
8119        preventDefault: function() { this.defaultPrevented = true; },
8120        isDefaultPrevented: function() { return this.defaultPrevented === true; },
8121        stopPropagation: noop,
8122        type: eventName,
8123        target: element
8124      };
8125
8126      // If a custom event was provided then extend our dummy event with it
8127      if (event.type) {
8128        dummyEvent = extend(dummyEvent, event);
8129      }
8130
8131      // Copy event handlers in case event handlers array is modified during execution.
8132      eventFnsCopy = shallowCopy(eventFns);
8133      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
8134
8135      forEach(eventFnsCopy, function(fn) {
8136        fn.apply(element, handlerArgs);
8137      });
8138
8139    }
8140  }
8141}, function(fn, name){
8142  /**
8143   * chaining functions
8144   */
8145  JQLite.prototype[name] = function(arg1, arg2, arg3) {
8146    var value;
8147    for(var i=0; i < this.length; i++) {
8148      if (isUndefined(value)) {
8149        value = fn(this[i], arg1, arg2, arg3);
8150        if (isDefined(value)) {
8151          // any function which returns a value needs to be wrapped
8152          value = jqLite(value);
8153        }
8154      } else {
8155        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
8156      }
8157    }
8158    return isDefined(value) ? value : this;
8159  };
8160
8161  // bind legacy bind/unbind to on/off
8162  JQLite.prototype.bind = JQLite.prototype.on;
8163  JQLite.prototype.unbind = JQLite.prototype.off;
8164});
8165
8166/**
8167 * Computes a hash of an 'obj'.
8168 * Hash of a:
8169 *  string is string
8170 *  number is number as string
8171 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
8172 *         that is also assigned to the $$hashKey property of the object.
8173 *
8174 * @param obj
8175 * @returns {string} hash string such that the same input will have the same hash string.
8176 *         The resulting string key is in 'type:hashKey' format.
8177 */
8178function hashKey(obj, nextUidFn) {
8179  var objType = typeof obj,
8180      key;
8181
8182  if (objType == 'function' || (objType == 'object' && obj !== null)) {
8183    if (typeof (key = obj.$$hashKey) == 'function') {
8184      // must invoke on object to keep the right this
8185      key = obj.$$hashKey();
8186    } else if (key === undefined) {
8187      key = obj.$$hashKey = (nextUidFn || nextUid)();
8188    }
8189  } else {
8190    key = obj;
8191  }
8192
8193  return objType + ':' + key;
8194}
8195
8196/**
8197 * HashMap which can use objects as keys
8198 */
8199function HashMap(array, isolatedUid) {
8200  if (isolatedUid) {
8201    var uid = 0;
8202    this.nextUid = function() {
8203      return ++uid;
8204    };
8205  }
8206  forEach(array, this.put, this);
8207}
8208HashMap.prototype = {
8209  /**
8210   * Store key value pair
8211   * @param key key to store can be any type
8212   * @param value value to store can be any type
8213   */
8214  put: function(key, value) {
8215    this[hashKey(key, this.nextUid)] = value;
8216  },
8217
8218  /**
8219   * @param key
8220   * @returns {Object} the value for the key
8221   */
8222  get: function(key) {
8223    return this[hashKey(key, this.nextUid)];
8224  },
8225
8226  /**
8227   * Remove the key/value pair
8228   * @param key
8229   */
8230  remove: function(key) {
8231    var value = this[key = hashKey(key, this.nextUid)];
8232    delete this[key];
8233    return value;
8234  }
8235};
8236
8237/**
8238 * @ngdoc function
8239 * @module ng
8240 * @name angular.injector
8241 * @kind function
8242 *
8243 * @description
8244 * Creates an injector function that can be used for retrieving services as well as for
8245 * dependency injection (see {@link guide/di dependency injection}).
8246 *
8247
8248 * @param {Array.<string|Function>}
8248 modules A list of module functions or their aliases. See
8249 *        {@link angular.module}. The `ng` module must be explicitly added.
8250 * @returns {function()} Injector function. See {@link auto.$injector $injector}.
8251 *
8252 * @example
8253 * Typical usage
8254 * ```js
8255 *   // create an injector
8256 *   var $injector = angular.injector(['ng']);
8257 *
8258 *   // use the injector to kick off your application
8259 *   // use the type inference to auto inject arguments, or use implicit injection
8260 *   $injector.invoke(function($rootScope, $compile, $document){
8261 *     $compile($document)($rootScope);
8262 *     $rootScope.$digest();
8263 *   });
8264 * ```
8265 *
8266 * Sometimes you want to get access to the injector of a currently running Angular app
8267 * from outside Angular. Perhaps, you want to inject and compile some markup after the
8268 * application has been bootstrapped. You can do this using the extra `injector()` added
8269 * to JQuery/jqLite elements. See {@link angular.element}.
8270 *
8271 * *This is fairly rare but could be the case if a third party library is injecting the
8272 * markup.*
8273 *
8274 * In the following example a new block of HTML containing a `ng-controller`
8275 * directive is added to the end of the document body by JQuery. We then compile and link
8276 * it into the current AngularJS scope.
8277 *
8278 * ```js
8279 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
8280 * $(document.body).append($div);
8281 *
8282 * angular.element(document).injector().invoke(function($compile) {
8283 *   var scope = angular.element($div).scope();
8284 *   $compile($div)(scope);
8285 * });
8286 * ```
8287 */
8288
8289
8290/**
8291 * @ngdoc module
8292 * @name auto
8293 * @description
8294 *
8295 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
8296 */
8297
8298var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
8299var FN_ARG_SPLIT = /,/;
8300var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
8301var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
8302var $injectorMinErr = minErr('$injector');
8303function annotate(fn) {
8304  var $inject,
8305      fnText,
8306      argDecl,
8307      last;
8308
8309  if (typeof fn === 'function') {
8310    if (!($inject = fn.$inject)) {
8311      $inject = [];
8312      if (fn.length) {
8313        fnText = fn.toString().replace(STRIP_COMMENTS, '');
8314        argDecl = fnText.match(FN_ARGS);
8315        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
8316          arg.replace(FN_ARG, function(all, underscore, name){
8317            $inject.push(name);
8318          });
8319        });
8320      }
8321      fn.$inject = $inject;
8322    }
8323  } else if (isArray(fn)) {
8324    last = fn.length - 1;
8325    assertArgFn(fn[last], 'fn');
8326    $inject = fn.slice(0, last);
8327  } else {
8328    assertArgFn(fn, 'fn', true);
8329  }
8330  return $inject;
8331}
8332
8333///////////////////////////////////////
8334
8335/**
8336 * @ngdoc service
8337 * @name $injector
8338 * @kind function
8339 *
8340 * @description
8341 *
8342 * `$injector` is used to retrieve object instances as defined by
8343 * {@link auto.$provide provider}, instantiate types, invoke methods,
8344 * and load modules.
8345 *
8346 * The following always holds true:
8347 *
8348 * ```js
8349 *   var $injector = angular.injector();
8350 *   expect($injector.get('$injector')).toBe($injector);
8351 *   expect($injector.invoke(function($injector){
8352 *     return $injector;
8353 *   }).toBe($injector);
8354 * ```
8355 *
8356 * # Injection Function Annotation
8357 *
8358 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
8359 * following are all valid ways of annotating function with injection arguments and are equivalent.
8360 *
8361 * ```js
8362 *   // inferred (only works if code not minified/obfuscated)
8363 *   $injector.invoke(function(serviceA){});
8364 *
8365 *   // annotated
8366 *   function explicit(serviceA) {};
8367 *   explicit.$inject = ['serviceA'];
8368 *   $injector.invoke(explicit);
8369 *
8370 *   // inline
8371 *   $injector.invoke(['serviceA', function(serviceA){}]);
8372 * ```
8373 *
8374 * ## Inference
8375 *
8376 * In JavaScript calling `toString()` on a function returns the function definition. The definition
8377 * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
8378 * minification, and obfuscation tools since these tools change the argument names.
8379 *
8380 * ## `$inject` Annotation
8381 * By adding an `$inject` property onto a function the injection parameters can be specified.
8382 *
8383 * ## Inline
8384 * As an array of injection names, where the last item in the array is the function to call.
8385 */
8386
8387/**
8388 * @ngdoc method
8389 * @name $injector#get
8390 *
8391 * @description
8392 * Return an instance of the service.
8393 *
8394 * @param {string} name The name of the instance to retrieve.
8395 * @return {*} The instance.
8396 */
8397
8398/**
8399 * @ngdoc method
8400 * @name $injector#invoke
8401 *
8402 * @description
8403 * Invoke the method and supply the method arguments from the `$injector`.
8404 *
8405 * @param {!Function} fn The function to invoke. Function parameters are injected according to the
8406 *   {@link guide/di $inject Annotation} rules.
8407 * @param {Object=} self The `this` for the invoked method.
8408 * @param {Object=} locals Optional object. If preset then any argument names are read from this
8409 *                         object first, before the `$injector` is consulted.
8410 * @returns {*} the value returned by the invoked `fn` function.
8411 */
8412
8413/**
8414 * @ngdoc method
8415 * @name $injector#has
8416 *
8417 * @description
8418 * Allows the user to query if the particular service exists.
8419 *
8420 * @param {string} Name of the service to query.
8421 * @returns {boolean} returns true if injector has given service.
8422 */
8423
8424/**
8425 * @ngdoc method
8426 * @name $injector#instantiate
8427 * @description
8428 * Create a new instance of JS type. The method takes a constructor function, invokes the new
8429 * operator, and supplies all of the arguments to the constructor function as specified by the
8430 * constructor annotation.
8431 *
8432 * @param {Function} Type Annotated constructor function.
8433 * @param {Object=} locals Optional object. If preset then any argument names are read from this
8434 * object first, before the `$injector` is consulted.
8435 * @returns {Object} new instance of `Type`.
8436 */
8437
8438/**
8439 * @ngdoc method
8440 * @name $injector#annotate
8441 *
8442 * @description
8443 * Returns an array of service names which the function is requesting for injection. This API is
8444 * used by the injector to determine which services need to be injected into the function when the
8445 * function is invoked. There are three ways in which the function can be annotated with the needed
8446 * dependencies.
8447 *
8448 * # Argument names
8449 *
8450 * The simplest form is to extract the dependencies from the arguments of the function. This is done
8451 * by converting the function into a string using `toString()` method and extracting the argument
8452 * names.
8453 * ```js
8454 *   // Given
8455 *   function MyController($scope, $route) {
8456 *     // ...
8457 *   }
8458 *
8459 *   // Then
8460 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
8461 * ```
8462 *
8463 * This method does not work with code minification / obfuscation. For this reason the following
8464 * annotation strategies are supported.
8465 *
8466 * # The `$inject` property
8467 *
8468 * If a function has an `$inject` property and its value is an array of strings, then the strings
8469 * represent names of services to be injected into the function.
8470 * ```js
8471 *   // Given
8472 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
8473 *     // ...
8474 *   }
8475 *   // Define function dependencies
8476 *   MyController['$inject'] = ['$scope', '$route'];
8477 *
8478 *   // Then
8479 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
8480 * ```
8481 *
8482 * # The array notation
8483 *
8484 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
8485 * is very inconvenient. In these situations using the array notation to specify the dependencies in
8486 * a way that survives minification is a better choice:
8487 *
8488 * ```js
8489 *   // We wish to write this (not minification / obfuscation safe)
8490 *   injector.invoke(function($compile, $rootScope) {
8491 *     // ...
8492 *   });
8493 *
8494 *   // We are forced to write break inlining
8495 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
8496 *     // ...
8497 *   };
8498 *   tmpFn.$inject = ['$compile', '$rootScope'];
8499 *   injector.invoke(tmpFn);
8500 *
8501 *   // To better support inline function the inline annotation is supported
8502 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
8503 *     // ...
8504 *   }]);
8505 *
8506 *   // Therefore
8507 *   expect(injector.annotate(
8508 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
8509 *    ).toEqual(['$compile', '$rootScope']);
8510 * ```
8511 *
8512 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
8513 * be retrieved as described above.
8514 *
8515 * @returns {Array.<string>} The names of the services which the function requires.
8516 */
8517
8518
8519
8520
8521/**
8522 * @ngdoc service
8523 * @name $provide
8524 *
8525 * @description
8526 *
8527 * The {@link auto.$provide $provide} service has a number of methods for registering components
8528 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
8529 * {@link angular.Module}.
8530 *
8531 * An Angular **service** is a singleton object created by a **service factory**.  These **service
8532 * factories** are functions which, in turn, are created by a **service provider**.
8533 * The **service providers** are constructor functions. When instantiated they must contain a
8534 * property called `$get`, which holds the **service factory** function.
8535 *
8536 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
8537 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
8538 * function to get the instance of the **service**.
8539 *
8540 * Often services have no configuration options and there is no need to add methods to the service
8541 * provider.  The provider will be no more than a constructor function with a `$get` property. For
8542 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
8543 * services without specifying a provider.
8544 *
8545 * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
8546 *     {@link auto.$injector $injector}
8547 * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
8548 *     providers and services.
8549 * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
8550 *     services, not providers.
8551 * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
8552 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
8553 *     given factory function.
8554 * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
8555 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
8556 *      a new object using the given constructor function.
8557 *
8558 * See the individual methods for more information and examples.
8559 */
8560
8561/**
8562 * @ngdoc method
8563 * @name $provide#provider
8564 * @description
8565 *
8566 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
8567 * are constructor functions, whose instances are responsible for "providing" a factory for a
8568 * service.
8569 *
8570 * Service provider names start with the name of the service they provide followed by `Provider`.
8571 * For example, the {@link ng.$log $log} service has a provider called
8572 * {@link ng.$logProvider $logProvider}.
8573 *
8574 * Service provider objects can have additional methods which allow configuration of the provider
8575 * and its service. Importantly, you can configure what kind of service is created by the `$get`
8576 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
8577 * method {@link ng.$logProvider#debugEnabled debugEnabled}
8578 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
8579 * console or not.
8580 *
8581 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
8582                        'Provider'` key.
8583 * @param {(Object|function())} provider If the provider is:
8584 *
8585 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
8586 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
8587 *   - `Constructor`: a new instance of the provider will be created using
8588 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
8589 *
8590 * @returns {Object} registered provider instance
8591
8592 * @example
8593 *
8594 * The following example shows how to create a simple event tracking service and register it using
8595 * {@link auto.$provide#provider $provide.provider()}.
8596 *
8597 * ```js
8598 *  // Define the eventTracker provider
8599 *  function EventTrackerProvider() {
8600 *    var trackingUrl = '/track';
8601 *
8602 *    // A provider method for configuring where the tracked events should been saved
8603 *    this.setTrackingUrl = function(url) {
8604 *      trackingUrl = url;
8605 *    };
8606 *
8607 *    // The service factory function
8608 *    this.$get = ['$http', function($http) {
8609 *      var trackedEvents = {};
8610 *      return {
8611 *        // Call this to track an event
8612 *        event: function(event) {
8613 *          var count = trackedEvents[event] || 0;
8614 *          count += 1;
8615 *          trackedEvents[event] = count;
8616 *          return count;
8617 *        },
8618 *        // Call this to save the tracked events to the trackingUrl
8619 *        save: function() {
8620 *          $http.post(trackingUrl, trackedEvents);
8621 *        }
8622 *      };
8623 *    }];
8624 *  }
8625 *
8626 *  describe('eventTracker', function() {
8627 *    var postSpy;
8628 *
8629 *    beforeEach(module(function($provide) {
8630 *      // Register the eventTracker provider
8631 *      $provide.provider('eventTracker', EventTrackerProvider);
8632 *    }));
8633 *
8634 *    beforeEach(module(function(eventTrackerProvider) {
8635 *      // Configure eventTracker provider
8636 *      eventTrackerProvider.setTrackingUrl('/custom-track');
8637 *    }));
8638 *
8639 *    it('tracks events', inject(function(eventTracker) {
8640 *      expect(eventTracker.event('login')).toEqual(1);
8641 *      expect(eventTracker.event('login')).toEqual(2);
8642 *    }));
8643 *
8644 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
8645 *      postSpy = spyOn($http, 'post');
8646 *      eventTracker.event('login');
8647 *      eventTracker.save();
8648 *      expect(postSpy).toHaveBeenCalled();
8649 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
8650 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
8651 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
8652 *    }));
8653 *  });
8654 * ```
8655 */
8656
8657/**
8658 * @ngdoc method
8659 * @name $provide#factory
8660 * @description
8661 *
8662 * Register a **service factory**, which will be called to return the service instance.
8663 * This is short for registering a service where its provider consists of only a `$get` property,
8664 * which is the given service factory function.
8665 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
8666 * configure your service in a provider.
8667 *
8668 * @param {string} name The name of the instance.
8669 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
8670 *                            for `$provide.provider(name, {$get: $getFn})`.
8671 * @returns {Object} registered provider instance
8672 *
8673 * @example
8674 * Here is an example of registering a service
8675 * ```js
8676 *   $provide.factory('ping', ['$http', function($http) {
8677 *     return function ping() {
8678 *       return $http.send('/ping');
8679 *     };
8680 *   }]);
8681 * ```
8682 * You would then inject and use this service like this:
8683 * ```js
8684 *   someModule.controller('Ctrl', ['ping', function(ping) {
8685 *     ping();
8686 *   }]);
8687 * ```
8688 */
8689
8690
8691/**
8692 * @ngdoc method
8693 * @name $provide#service
8694 * @description
8695 *
8696 * Register a **service constructor**, which will be invoked with `new` to create the service
8697 * instance.
8698 * This is short for registering a service where its provider's `$get` property is the service
8699 * constructor function that will be used to instantiate the service instance.
8700 *
8701 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
8702 * as a type/class.
8703 *
8704 * @param {string} name The name of the instance.
8705 * @param {Function} constructor A class (constructor function) that will be instantiated.
8706 * @returns {Object} registered provider instance
8707 *
8708 * @example
8709 * Here is an example of registering a service using
8710 * {@link auto.$provide#service $provide.service(class)}.
8711 * ```js
8712 *   var Ping = function($http) {
8713 *     this.$http = $http;
8714 *   };
8715 *
8716 *   Ping.$inject = ['$http'];
8717 *
8718 *   Ping.prototype.send = function() {
8719 *     return this.$http.get('/ping');
8720 *   };
8721 *   $provide.service('ping', Ping);
8722 * ```
8723 * You would then inject and use this service like this:
8724 * ```js
8725 *   someModule.controller('Ctrl', ['ping', function(ping) {
8726 *     ping.send();
8727 *   }]);
8728 * ```
8729 */
8730
8731
8732/**
8733 * @ngdoc method
8734 * @name $provide#value
8735 * @description
8736 *
8737 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
8738 * number, an array, an object or a function.  This is short for registering a service where its
8739 * provider's `$get` property is a factory function that takes no arguments and returns the **value
8740 * service**.
8741 *
8742 * Value services are similar to constant services, except that they cannot be injected into a
8743 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
8744 * an Angular
8745 * {@link auto.$provide#decorator decorator}.
8746 *
8747 * @param {string} name The name of the instance.
8748 * @param {*} value The value.
8749 * @returns {Object} registered provider instance
8750 *
8751 * @example
8752 * Here are some examples of creating value services.
8753 * ```js
8754 *   $provide.value('ADMIN_USER', 'admin');
8755 *
8756 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
8757 *
8758 *   $provide.value('halfOf', function(value) {
8759 *     return value / 2;
8760 *   });
8761 * ```
8762 */
8763
8764
8765/**
8766 * @ngdoc method
8767 * @name $provide#constant
8768 * @description
8769 *
8770 * Register a **constant service**, such as a string, a number, an array, an object or a function,
8771 * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
8772 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
8773 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
8774 *
8775 * @param {string} name The name of the constant.
8776 * @param {*} value The constant value.
8777 * @returns {Object} registered instance
8778 *
8779 * @example
8780 * Here a some examples of creating constants:
8781 * ```js
8782 *   $provide.constant('SHARD_HEIGHT', 306);
8783 *
8784 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
8785 *
8786 *   $provide.constant('double', function(value) {
8787 *     return value * 2;
8788 *   });
8789 * ```
8790 */
8791
8792
8793/**
8794 * @ngdoc method
8795 * @name $provide#decorator
8796 * @description
8797 *
8798 * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
8799 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
8800 * service. The object returned by the decorator may be the original service, or a new service
8801 * object which replaces or wraps and delegates to the original service.
8802 *
8803 * @param {string} name The name of the service to decorate.
8804 * @param {function()} decorator This function will be invoked when the service needs to be
8805 *    instantiated and should return the decorated service instance. The function is called using
8806 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
8807 *    Local injection arguments:
8808 *
8809 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
8810 *      decorated or delegated to.
8811 *
8812 * @example
8813 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
8814 * calls to {@link ng.$log#error $log.warn()}.
8815 * ```js
8816 *   $provide.decorator('$log', ['$delegate', function($delegate) {
8817 *     $delegate.warn = $delegate.error;
8818 *     return $delegate;
8819 *   }]);
8820 * ```
8821 */
8822
8823
8824function createInjector(modulesToLoad) {
8825  var INSTANTIATING = {},
8826      providerSuffix = 'Provider',
8827      path = [],
8828      loadedModules = new HashMap([], true),
8829      providerCache = {
8830        $provide: {
8831            provider: supportObject(provider),
8832            factory: supportObject(factory),
8833            service: supportObject(service),
8834            value: supportObject(value),
8835            constant: supportObject(constant),
8836            decorator: decorator
8837          }
8838      },
8839      providerInjector = (providerCache.$injector =
8840          createInternalInjector(providerCache, function() {
8841            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
8842          })),
8843      instanceCache = {},
8844      instanceInjector = (instanceCache.$injector =
8845          createInternalInjector(instanceCache, function(servicename) {
8846            var provider = providerInjector.get(servicename + providerSuffix);
8847            return instanceInjector.invoke(provider.$get, provider);
8848          }));
8849
8850
8851  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
8852
8853  return instanceInjector;
8854
8855  ////////////////////////////////////
8856  // $provider
8857  ////////////////////////////////////
8858
8859  function supportObject(delegate) {
8860    return function(key, value) {
8861      if (isObject(key)) {
8862        forEach(key, reverseParams(delegate));
8863      } else {
8864        return delegate(key, value);
8865      }
8866    };
8867  }
8868
8869  function provider(name, provider_) {
8870    assertNotHasOwnProperty(name, 'service');
8871    if (isFunction(provider_) || isArray(provider_)) {
8872      provider_ = providerInjector.instantiate(provider_);
8873    }
8874    if (!provider_.$get) {
8875      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
8876    }
8877    return providerCache[name + providerSuffix] = provider_;
8878  }
8879
8880  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
8881
8882  function service(name, constructor) {
8883    return factory(name, ['$injector', function($injector) {
8884      return $injector.instantiate(constructor);
8885    }]);
8886  }
8887
8888  function value(name, val) { return factory(name, valueFn(val)); }
8889
8890  function constant(name, value) {
8891    assertNotHasOwnProperty(name, 'constant');
8892    providerCache[name] = value;
8893    instanceCache[name] = value;
8894  }
8895
8896  function decorator(serviceName, decorFn) {
8897    var origProvider = providerInjector.get(serviceName + providerSuffix),
8898        orig$get = origProvider.$get;
8899
8900    origProvider.$get = function() {
8901      var origInstance = instanceInjector.invoke(orig$get, origProvider);
8902      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
8903    };
8904  }
8905
8906  ////////////////////////////////////
8907  // Module Loading
8908  ////////////////////////////////////
8909  function loadModules(modulesToLoad){
8910    var runBlocks = [], moduleFn, invokeQueue, i, ii;
8911    forEach(modulesToLoad, function(module) {
8912      if (loadedModules.get(module)) return;
8913      loadedModules.put(module, true);
8914
8915      try {
8916        if (isString(module)) {
8917          moduleFn = angularModule(module);
8918          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
8919
8920          for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
8921            var invokeArgs = invokeQueue[i],
8922                provider = providerInjector.get(invokeArgs[0]);
8923
8924            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
8925          }
8926        } else if (isFunction(module)) {
8927            runBlocks.push(providerInjector.invoke(module));
8928        } else if (isArray(module)) {
8929            runBlocks.push(providerInjector.invoke(module));
8930        } else {
8931          assertArgFn(module, 'module');
8932        }
8933      } catch (e) {
8934        if (isArray(module)) {
8935          module = module[module.length - 1];
8936        }
8937        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
8938          // Safari & FF's stack traces don't contain error.message content
8939          // unlike those of Chrome and IE
8940          // So if stack doesn't contain message, we create a new string that contains both.
8941          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
8942          /* jshint -W022 */
8943          e = e.message + '\n' + e.stack;
8944        }
8945        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
8946                  module, e.stack || e.message || e);
8947      }
8948    });
8949    return runBlocks;
8950  }
8951
8952  ////////////////////////////////////
8953  // internal Injector
8954  ////////////////////////////////////
8955
8956  function createInternalInjector(cache, factory) {
8957
8958    function getService(serviceName) {
8959      if (cache.hasOwnProperty(serviceName)) {
8960        if (cache[serviceName] === INSTANTIATING) {
8961          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
8962                    serviceName + ' <- ' + path.join(' <- '));
8963        }
8964        return cache[serviceName];
8965      } else {
8966        try {
8967          path.unshift(serviceName);
8968          cache[serviceName] = INSTANTIATING;
8969          return cache[serviceName] = factory(serviceName);
8970        } catch (err) {
8971          if (cache[serviceName] === INSTANTIATING) {
8972            delete cache[serviceName];
8973          }
8974          throw err;
8975        } finally {
8976          path.shift();
8977        }
8978      }
8979    }
8980
8981    function invoke(fn, self, locals){
8982      var args = [],
8983          $inject = annotate(fn),
8984          length, i,
8985          key;
8986
8987      for(i = 0, length = $inject.length; i < length; i++) {
8988        key = $inject[i];
8989        if (typeof key !== 'string') {
8990          throw $injectorMinErr('itkn',
8991                  'Incorrect injection token! Expected service name as string, got {0}', key);
8992        }
8993        args.push(
8994          locals && locals.hasOwnProperty(key)
8995          ? locals[key]
8996          : getService(key)
8997        );
8998      }
8999      if (isArray(fn)) {
9000        fn = fn[length];
9001      }
9002
9003      // http://jsperf.com/angularjs-invoke-apply-vs-switch
9004      // #5388
9005      return fn.apply(self, args);
9006    }
9007
9008    function instantiate(Type, locals) {
9009      var Constructor = function() {},
9010          instance, returnedValue;
9011
9012      // Check if Type is annotated and use just the given function at n-1 as parameter
9013      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
9014      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
9015      instance = new Constructor();
9016      returnedValue = invoke(Type, instance, locals);
9017
9018      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
9019    }
9020
9021    return {
9022      invoke: invoke,
9023      instantiate: instantiate,
9024      get: getService,
9025      annotate: annotate,
9026      has: function(name) {
9027        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
9028      }
9029    };
9030  }
9031}
9032
9033/**
9034 * @ngdoc service
9035 * @name $anchorScroll
9036 * @kind function
9037 * @requires $window
9038 * @requires $location
9039 * @requires $rootScope
9040 *
9041 * @description
9042 * When called, it checks current value of `$location.hash()` and scrolls to the related element,
9043 * according to rules specified in
9044 * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
9045 *
9046 * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
9047 * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
9048 *
9049 * @example
9050   <example>
9051     <file name="index.html">
9052       <div id="scrollArea" ng-controller="ScrollCtrl">
9053         <a ng-click="gotoBottom()">Go to bottom</a>
9054         <a id="bottom"></a> You're at the bottom!
9055       </div>
9056     </file>
9057     <file name="script.js">
9058       function ScrollCtrl($scope, $location, $anchorScroll) {
9059         $scope.gotoBottom = function (){
9060           // set the location.hash to the id of
9061           // the element you wish to scroll to.
9062           $location.hash('bottom');
9063
9064           // call $anchorScroll()
9065           $anchorScroll();
9066         };
9067       }
9068     </file>
9069     <file name="style.css">
9070       #scrollArea {
9071         height: 350px;
9072         overflow: auto;
9073       }
9074
9075       #bottom {
9076         display: block;
9077         margin-top: 2000px;
9078       }
9079     </file>
9080   </example>
9081 */
9082function $AnchorScrollProvider() {
9083
9084  var autoScrollingEnabled = true;
9085
9086  this.disableAutoScrolling = function() {
9087    autoScrollingEnabled = false;
9088  };
9089
9090  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
9091    var document = $window.document;
9092
9093    // helper function to get first anchor from a NodeList
9094    // can't use filter.filter, as it accepts only instances of Array
9095    // and IE can't convert NodeList to an array using [].slice
9096    // TODO(vojta): use filter if we change it to accept lists as well
9097    function getFirstAnchor(list) {
9098      var result = null;
9099      forEach(list, function(element) {
9100        if (!result && lowercase(element.nodeName) === 'a') result = element;
9101      });
9102      return result;
9103    }
9104
9105    function scroll() {
9106      var hash = $location.hash(), elm;
9107
9108      // empty hash, scroll to the top of the page
9109      if (!hash) $window.scrollTo(0, 0);
9110
9111      // element with given id
9112      else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
9113
9114      // first anchor with given name :-D
9115      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
9116
9117      // no element and hash == 'top', scroll to the top of the page
9118      else if (hash === 'top') $window.scrollTo(0, 0);
9119    }
9120
9121    // does not scroll when user clicks on anchor link that is currently on
9122    // (no url change, no $location.hash() change), browser native does scroll
9123    if (autoScrollingEnabled) {
9124      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
9125        function autoScrollWatchAction() {
9126          $rootScope.$evalAsync(scroll);
9127        });
9128    }
9129
9130    return scroll;
9131  }];
9132}
9133
9134var $animateMinErr = minErr('$animate');
9135
9136/**
9137 * @ngdoc provider
9138 * @name $animateProvider
9139 *
9140 * @description
9141 * Default implementation of $animate that doesn't perform any animations, instead just
9142 * synchronously performs DOM
9143 * updates and calls done() callbacks.
9144 *
9145 * In order to enable animations the ngAnimate module has to be loaded.
9146 *
9147 * To see the functional implementation check out src/ngAnimate/animate.js
9148 */
9149var $AnimateProvider = ['$provide', function($provide) {
9150
9151
9152  this.$$selectors = {};
9153
9154
9155  /**
9156   * @ngdoc method
9157   * @name $animateProvider#register
9158   *
9159   * @description
9160   * Registers a new injectable animation factory function. The factory function produces the
9161   * animation object which contains callback functions for each event that is expected to be
9162   * animated.
9163   *
9164   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
9165   *   must be called once the element animation is complete. If a function is returned then the
9166   *   animation service will use this function to cancel the animation whenever a cancel event is
9167   *   triggered.
9168   *
9169   *
9170   * ```js
9171   *   return {
9172     *     eventFn : function(element, done) {
9173     *       //code to run the animation
9174     *       //once complete, then run done()
9175     *       return function cancellationFunction() {
9176     *         //code to cancel the animation
9177     *       }
9178     *     }
9179     *   }
9180   * ```
9181   *
9182   * @param {string} name The name of the animation.
9183   * @param {Function} factory The factory function that will be executed to return the animation
9184   *                           object.
9185   */
9186  this.register = function(name, factory) {
9187    var key = name + '-animation';
9188    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
9189        "Expecting class selector starting with '.' got '{0}'.", name);
9190    this.$$selectors[name.substr(1)] = key;
9191    $provide.factory(key, factory);
9192  };
9193
9194  /**
9195   * @ngdoc method
9196   * @name $animateProvider#classNameFilter
9197   *
9198   * @description
9199   * Sets and/or returns the CSS class regular expression that is checked when performing
9200   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
9201   * therefore enable $animate to attempt to perform an animation on any element.
9202   * When setting the classNameFilter value, animations will only be performed on elements
9203   * that successfully match the filter expression. This in turn can boost performance
9204   * for low-powered devices as well as applications containing a lot of structural operations.
9205   * @param {RegExp=} expression The className expression which will be checked against all animations
9206   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
9207   */
9208  this.classNameFilter = function(expression) {
9209    if(arguments.length === 1) {
9210      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
9211    }
9212    return this.$$classNameFilter;
9213  };
9214
9215  this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
9216
9217    function async(fn) {
9218      fn && $$asyncCallback(fn);
9219    }
9220
9221    /**
9222     *
9223     * @ngdoc service
9224     * @name $animate
9225     * @description The $animate service provides rudimentary DOM manipulation functions to
9226     * insert, remove and move elements within the DOM, as well as adding and removing classes.
9227     * This service is the core service used by the ngAnimate $animator service which provides
9228     * high-level animation hooks for CSS and JavaScript.
9229     *
9230     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
9231     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
9232     * manipulation operations.
9233     *
9234     * To learn more about enabling animation support, click here to visit the {@link ngAnimate
9235     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
9236     * page}.
9237     */
9238    return {
9239
9240      /**
9241       *
9242       * @ngdoc method
9243       * @name $animate#enter
9244       * @kind function
9245       * @description Inserts the element into the DOM either after the `after` element or within
9246       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
9247       * @param {DOMElement} element the element which will be inserted into the DOM
9248       * @param {DOMElement} parent the parent element which will append the element as
9249       *   a child (if the after element is not present)
9250       * @param {DOMElement} after the sibling element which will append the element
9251       *   after itself
9252       * @param {Function=} done callback function that will be called after the element has been
9253       *   inserted into the DOM
9254       */
9255      enter : function(element, parent, after, done) {
9256        if (after) {
9257          after.after(element);
9258        } else {
9259          if (!parent || !parent[0]) {
9260            parent = after.parent();
9261          }
9262          parent.append(element);
9263        }
9264        async(done);
9265      },
9266
9267      /**
9268       *
9269       * @ngdoc method
9270       * @name $animate#leave
9271       * @kind function
9272       * @description Removes the element from the DOM. Once complete, the done() callback will be
9273       *   fired (if provided).
9274       * @param {DOMElement} element the element which will be removed from the DOM
9275       * @param {Function=} done callback function that will be called after the element has been
9276       *   removed from the DOM
9277       */
9278      leave : function(element, done) {
9279        element.remove();
9280        async(done);
9281      },
9282
9283      /**
9284       *
9285       * @ngdoc method
9286       * @name $animate#move
9287       * @kind function
9288       * @description Moves the position of the provided element within the DOM to be placed
9289       * either after the `after` element or inside of the `parent` element. Once complete, the
9290       * done() callback will be fired (if provided).
9291       *
9292       * @param {DOMElement} element the element which will be moved around within the
9293       *   DOM
9294       * @param {DOMElement} parent the parent element where the element will be
9295       *   inserted into (if the after element is not present)
9296       * @param {DOMElement} after the sibling element where the element will be
9297       *   positioned next to
9298       * @param {Function=} done the callback function (if provided) that will be fired after the
9299       *   element has been moved to its new position
9300       */
9301      move : function(element, parent, after, done) {
9302        // Do not remove element before insert. Removing will cause data associated with the
9303        // element to be dropped. Insert will implicitly do the remove.
9304        this.enter(element, parent, after, done);
9305      },
9306
9307      /**
9308       *
9309       * @ngdoc method
9310       * @name $animate#addClass
9311       * @kind function
9312       * @description Adds the provided className CSS class value to the provided element. Once
9313       * complete, the done() callback will be fired (if provided).
9314       * @param {DOMElement} element the element which will have the className value
9315       *   added to it
9316       * @param {string} className the CSS class which will be added to the element
9317       * @param {Function=} done the callback function (if provided) that will be fired after the
9318       *   className value has been added to the element
9319       */
9320      addClass : function(element, className, done) {
9321        className = isString(className) ?
9322                      className :
9323                      isArray(className) ? className.join(' ') : '';
9324        forEach(element, function (element) {
9325          jqLiteAddClass(element, className);
9326        });
9327        async(done);
9328      },
9329
9330      /**
9331       *
9332       * @ngdoc method
9333       * @name $animate#removeClass
9334       * @kind function
9335       * @description Removes the provided className CSS class value from the provided element.
9336       * Once complete, the done() callback will be fired (if provided).
9337       * @param {DOMElement} element the element which will have the className value
9338       *   removed from it
9339       * @param {string} className the CSS class which will be removed from the element
9340       * @param {Function=} done the callback function (if provided) that will be fired after the
9341       *   className value has been removed from the element
9342       */
9343      removeClass : function(element, className, done) {
9344        className = isString(className) ?
9345                      className :
9346                      isArray(className) ? className.join(' ') : '';
9347        forEach(element, function (element) {
9348          jqLiteRemoveClass(element, className);
9349        });
9350        async(done);
9351      },
9352
9353      /**
9354       *
9355       * @ngdoc method
9356       * @name $animate#setClass
9357       * @kind function
9358       * @description Adds and/or removes the given CSS classes to and from the element.
9359       * Once complete, the done() callback will be fired (if provided).
9360       * @param {DOMElement} element the element which will have its CSS classes changed
9361       *   removed from it
9362       * @param {string} add the CSS classes which will be added to the element
9363       * @param {string} remove the CSS class which will be removed from the element
9364       * @param {Function=} done the callback function (if provided) that will be fired after the
9365       *   CSS classes have been set on the element
9366       */
9367      setClass : function(element, add, remove, done) {
9368        forEach(element, function (element) {
9369          jqLiteAddClass(element, add);
9370          jqLiteRemoveClass(element, remove);
9371        });
9372        async(done);
9373      },
9374
9375      enabled : noop
9376    };
9377  }];
9378}];
9379
9380function $$AsyncCallbackProvider(){
9381  this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
9382    return $$rAF.supported
9383      ? function(fn) { return $$rAF(fn); }
9384      : function(fn) {
9385        return $timeout(fn, 0, false);
9386      };
9387  }];
9388}
9389
9390/**
9391 * ! This is a private undocumented service !
9392 *
9393 * @name $browser
9394 * @requires $log
9395 * @description
9396 * This object has two goals:
9397 *
9398 * - hide all the global state in the browser caused by the window object
9399 * - abstract away all the browser specific features and inconsistencies
9400 *
9401 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
9402 * service, which can be used for convenient testing of the application without the interaction with
9403 * the real browser apis.
9404 */
9405/**
9406 * @param {object} window The global window object.
9407 * @param {object} document jQuery wrapped document.
9408 * @param {function()} XHR XMLHttpRequest constructor.
9409 * @param {object} $log console.log or an object with the same interface.
9410 * @param {object} $sniffer $sniffer service
9411 */
9412function Browser(window, document, $log, $sniffer) {
9413  var self = this,
9414      rawDocument = document[0],
9415      location = window.location,
9416      history = window.history,
9417      setTimeout = window.setTimeout,
9418      clearTimeout = window.clearTimeout,
9419      pendingDeferIds = {};
9420
9421  self.isMock = false;
9422
9423  var outstandingRequestCount = 0;
9424  var outstandingRequestCallbacks = [];
9425
9426  // TODO(vojta): remove this temporary api
9427  self.$$completeOutstandingRequest = completeOutstandingRequest;
9428  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
9429
9430  /**
9431   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
9432   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
9433   */
9434  function completeOutstandingRequest(fn) {
9435    try {
9436      fn.apply(null, sliceArgs(arguments, 1));
9437    } finally {
9438      outstandingRequestCount--;
9439      if (outstandingRequestCount === 0) {
9440        while(outstandingRequestCallbacks.length) {
9441          try {
9442            outstandingRequestCallbacks.pop()();
9443          } catch (e) {
9444            $log.error(e);
9445          }
9446        }
9447      }
9448    }
9449  }
9450
9451  /**
9452   * @private
9453   * Note: this method is used only by scenario runner
9454   * TODO(vojta): prefix this method with $$ ?
9455   * @param {function()} callback Function that will be called when no outstanding request
9456   */
9457  self.notifyWhenNoOutstandingRequests = function(callback) {
9458    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
9459    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
9460    // regular poller would result in flaky tests.
9461    forEach(pollFns, function(pollFn){ pollFn(); });
9462
9463    if (outstandingRequestCount === 0) {
9464      callback();
9465    } else {
9466      outstandingRequestCallbacks.push(callback);
9467    }
9468  };
9469
9470  //////////////////////////////////////////////////////////////
9471  // Poll Watcher API
9472  //////////////////////////////////////////////////////////////
9473  var pollFns = [],
9474      pollTimeout;
9475
9476  /**
9477   * @name $browser#addPollFn
9478   *
9479   * @param {function()} fn Poll function to add
9480   *
9481   * @description
9482   * Adds a function to the list of functions that poller periodically executes,
9483   * and starts polling if not started yet.
9484   *
9485   * @returns {function()} the added function
9486   */
9487  self.addPollFn = function(fn) {
9488    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
9489    pollFns.push(fn);
9490    return fn;
9491  };
9492
9493  /**
9494   * @param {number} interval How often should browser call poll functions (ms)
9495   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
9496   *
9497   * @description
9498   * Configures the poller to run in the specified intervals, using the specified
9499   * setTimeout fn and kicks it off.
9500   */
9501  function startPoller(interval, setTimeout) {
9502    (function check() {
9503      forEach(pollFns, function(pollFn){ pollFn(); });
9504      pollTimeout = setTimeout(check, interval);
9505    })();
9506  }
9507
9508  //////////////////////////////////////////////////////////////
9509  // URL API
9510  //////////////////////////////////////////////////////////////
9511
9512  var lastBrowserUrl = location.href,
9513      baseElement = document.find('base'),
9514      newLocation = null;
9515
9516  /**
9517   * @name $browser#url
9518   *
9519   * @description
9520   * GETTER:
9521   * Without any argument, this method just returns current value of location.href.
9522   *
9523   * SETTER:
9524   * With at least one argument, this method sets url to new value.
9525   * If html5 history api supported, pushState/replaceState is used, otherwise
9526   * location.href/location.replace is used.
9527   * Returns its own instance to allow chaining
9528   *
9529   * NOTE: this api is intended for use only by the $location service. Please use the
9530   * {@link ng.$location $location service} to change url.
9531   *
9532   * @param {string} url New url (when used as setter)
9533   * @param {boolean=} replace Should new url replace current history record ?
9534   */
9535  self.url = function(url, replace) {
9536    // Android Browser BFCache causes location, history reference to become stale.
9537    if (location !== window.location) location = window.location;
9538    if (history !== window.history) history = window.history;
9539
9540    // setter
9541    if (url) {
9542      if (lastBrowserUrl == url) return;
9543      lastBrowserUrl = url;
9544      if ($sniffer.history) {
9545        if (replace) history.replaceState(null, '', url);
9546        else {
9547          history.pushState(null, '', url);
9548          // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
9549          baseElement.attr('href', baseElement.attr('href'));
9550        }
9551      } else {
9552        newLocation = url;
9553        if (replace) {
9554          location.replace(url);
9555        } else {
9556          location.href = url;
9557        }
9558      }
9559      return self;
9560    // getter
9561    } else {
9562      // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
9563      //   methods not updating location.href synchronously.
9564      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
9565      return newLocation || location.href.replace(/%27/g,"'");
9566    }
9567  };
9568
9569  var urlChangeListeners = [],
9570      urlChangeInit = false;
9571
9572  function fireUrlChange() {
9573    newLocation = null;
9574    if (lastBrowserUrl == self.url()) return;
9575
9576    lastBrowserUrl = self.url();
9577    forEach(urlChangeListeners, function(listener) {
9578      listener(self.url());
9579    });
9580  }
9581
9582  /**
9583   * @name $browser#onUrlChange
9584   *
9585   * @description
9586   * Register callback function that will be called, when url changes.
9587   *
9588   * It's only called when the url is changed from outside of angular:
9589   * - user types different url into address bar
9590   * - user clicks on history (forward/back) button
9591   * - user clicks on a link
9592   *
9593   * It's not called when url is changed by $browser.url() method
9594   *
9595   * The listener gets called with new url as parameter.
9596   *
9597   * NOTE: this api is intended for use only by the $location service. Please use the
9598   * {@link ng.$location $location service} to monitor url changes in angular apps.
9599   *
9600   * @param {function(string)} listener Listener function to be called when url changes.
9601   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
9602   */
9603  self.onUrlChange = function(callback) {
9604    // TODO(vojta): refactor to use node's syntax for events
9605    if (!urlChangeInit) {
9606      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
9607      // don't fire popstate when user change the address bar and don't fire hashchange when url
9608      // changed by push/replaceState
9609
9610      // html5 history api - popstate event
9611      if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
9612      // hashchange event
9613      if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
9614      // polling
9615      else self.addPollFn(fireUrlChange);
9616
9617      urlChangeInit = true;
9618    }
9619
9620    urlChangeListeners.push(callback);
9621    return callback;
9622  };
9623
9624  /**
9625   * Checks whether the url has changed outside of Angular.
9626   * Needs to be exported to be able to check for changes that have been done in sync,
9627   * as hashchange/popstate events fire in async.
9628   */
9629  self.$$checkUrlChange = fireUrlChange;
9630
9631  //////////////////////////////////////////////////////////////
9632  // Misc API
9633  //////////////////////////////////////////////////////////////
9634
9635  /**
9636   * @name $browser#baseHref
9637   *
9638   * @description
9639   * Returns current <base href>
9640   * (always relative - without domain)
9641   *
9642   * @returns {string} The current base href
9643   */
9644  self.baseHref = function() {
9645    var href = baseElement.attr('href');
9646    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
9647  };
9648
9649  //////////////////////////////////////////////////////////////
9650  // Cookies API
9651  //////////////////////////////////////////////////////////////
9652  var lastCookies = {};
9653  var lastCookieString = '';
9654  var cookiePath = self.baseHref();
9655
9656  /**
9657   * @name $browser#cookies
9658   *
9659   * @param {string=} name Cookie name
9660   * @param {string=} value Cookie value
9661   *
9662   * @description
9663   * The cookies method provides a 'private' low level access to browser cookies.
9664   * It is not meant to be used directly, use the $cookie service instead.
9665   *
9666   * The return values vary depending on the arguments that the method was called with as follows:
9667   *
9668   * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
9669   *   it
9670   * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
9671   * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
9672   *   way)
9673   *
9674   * @returns {Object} Hash of all cookies (if called without any parameter)
9675   */
9676  self.cookies = function(name, value) {
9677    /* global escape: false, unescape: false */
9678    var cookieLength, cookieArray, cookie, i, index;
9679
9680    if (name) {
9681      if (value === undefined) {
9682        rawDocument.cookie = escape(name) + "=;
9682path=" + cookiePath +
9683                                ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
9684      } else {
9685        if (isString(value)) {
9686          cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
9687                                ';path=' + cookiePath).length + 1;
9688
9689          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
9690          // - 300 cookies
9691          // - 20 cookies per unique domain
9692          // - 4096 bytes per cookie
9693          if (cookieLength > 4096) {
9694            $log.warn("Cookie '"+ name +
9695              "' possibly not set or overflowed because it was too large ("+
9696              cookieLength + " > 4096 bytes)!");
9697          }
9698        }
9699      }
9700    } else {
9701      if (rawDocument.cookie !== lastCookieString) {
9702        lastCookieString = rawDocument.cookie;
9703        cookieArray = lastCookieString.split("; ");
9704        lastCookies = {};
9705
9706        for (i = 0; i < cookieArray.length; i++) {
9707          cookie = cookieArray[i];
9708          index = cookie.indexOf('=');
9709          if (index > 0) { //ignore nameless cookies
9710            name = unescape(cookie.substring(0, index));
9711            // the first value that is seen for a cookie is the most
9712            // specific one.  values for the same cookie name that
9713            // follow are for less specific paths.
9714            if (lastCookies[name] === undefined) {
9715              lastCookies[name] = unescape(cookie.substring(index + 1));
9716            }
9717          }
9718        }
9719      }
9720      return lastCookies;
9721    }
9722  };
9723
9724
9725  /**
9726   * @name $browser#defer
9727   * @param {function()} fn A function, who's execution should be deferred.
9728   * @param {number=} [delay=0] of milliseconds to defer the function execution.
9729   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
9730   *
9731   * @description
9732   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
9733   *
9734   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
9735   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
9736   * via `$browser.defer.flush()`.
9737   *
9738   */
9739  self.defer = function(fn, delay) {
9740    var timeoutId;
9741    outstandingRequestCount++;
9742    timeoutId = setTimeout(function() {
9743      delete pendingDeferIds[timeoutId];
9744      completeOutstandingRequest(fn);
9745    }, delay || 0);
9746    pendingDeferIds[timeoutId] = true;
9747    return timeoutId;
9748  };
9749
9750
9751  /**
9752   * @name $browser#defer.cancel
9753   *
9754   * @description
9755   * Cancels a deferred task identified with `deferId`.
9756   *
9757   * @param {*} deferId Token returned by the `$browser.defer` function.
9758   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
9759   *                    canceled.
9760   */
9761  self.defer.cancel = function(deferId) {
9762    if (pendingDeferIds[deferId]) {
9763      delete pendingDeferIds[deferId];
9764      clearTimeout(deferId);
9765      completeOutstandingRequest(noop);
9766      return true;
9767    }
9768    return false;
9769  };
9770
9771}
9772
9773function $BrowserProvider(){
9774  this.$get = ['$window', '$log', '$sniffer', '$document',
9775      function( $window,   $log,   $sniffer,   $document){
9776        return new Browser($window, $document, $log, $sniffer);
9777      }];
9778}
9779
9780/**
9781 * @ngdoc service
9782 * @name $cacheFactory
9783 *
9784 * @description
9785 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
9786 * them.
9787 *
9788 * ```js
9789 *
9790 *  var cache = $cacheFactory('cacheId');
9791 *  expect($cacheFactory.get('cacheId')).toBe(cache);
9792 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
9793 *
9794 *  cache.put("key", "value");
9795 *  cache.put("another key", "another value");
9796 *
9797 *  // We've specified no options on creation
9798 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
9799 *
9800 * ```
9801 *
9802 *
9803 * @param {string} cacheId Name or id of the newly created cache.
9804 * @param {object=} options Options object that specifies the cache behavior. Properties:
9805 *
9806 *   - `{number=}` `capacity` — turns the cache into LRU cache.
9807 *
9808 * @returns {object} Newly created cache object with the following set of methods:
9809 *
9810 * - `{object}` `info()` — Returns id, size, and options of cache.
9811 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
9812 *   it.
9813 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
9814 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
9815 * - `{void}` `removeAll()` — Removes all cached values.
9816 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
9817 *
9818 * @example
9819   <example module="cacheExampleApp">
9820     <file name="index.html">
9821       <div ng-controller="CacheController">
9822         <input ng-model="newCacheKey" placeholder="Key">
9823         <input ng-model="newCacheValue" placeholder="Value">
9824         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
9825
9826         <p ng-if="keys.length">Cached Values</p>
9827         <div ng-repeat="key in keys">
9828           <span ng-bind="key"></span>
9829           <span>: </span>
9830           <b ng-bind="cache.get(key)"></b>
9831         </div>
9832
9833         <p>Cache Info</p>
9834         <div ng-repeat="(key, value) in cache.info()">
9835           <span ng-bind="key"></span>
9836           <span>: </span>
9837           <b ng-bind="value"></b>
9838         </div>
9839       </div>
9840     </file>
9841     <file name="script.js">
9842       angular.module('cacheExampleApp', []).
9843         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
9844           $scope.keys = [];
9845           $scope.cache = $cacheFactory('cacheId');
9846           $scope.put = function(key, value) {
9847             if ($scope.cache.get(key) === undefined) {
9848               $scope.keys.push(key);
9849             }
9850             $scope.cache.put(key, value === undefined ? null : value);
9851           };
9852         }]);
9853     </file>
9854     <file name="style.css">
9855       p {
9856         margin: 10px 0 3px;
9857       }
9858     </file>
9859   </example>
9860 */
9861function $CacheFactoryProvider() {
9862
9863  this.$get = function() {
9864    var caches = {};
9865
9866    function cacheFactory(cacheId, options) {
9867      if (cacheId in caches) {
9868        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
9869      }
9870
9871      var size = 0,
9872          stats = extend({}, options, {id: cacheId}),
9873          data = {},
9874          capacity = (options && options.capacity) || Number.MAX_VALUE,
9875          lruHash = {},
9876          freshEnd = null,
9877          staleEnd = null;
9878
9879      /**
9880       * @ngdoc type
9881       * @name $cacheFactory.Cache
9882       *
9883       * @description
9884       * A cache object used to store and retrieve data, primarily used by
9885       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
9886       * templates and other data.
9887       *
9888       * ```js
9889       *  angular.module('superCache')
9890       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
9891       *      return $cacheFactory('super-cache');
9892       *    }]);
9893       * ```
9894       *
9895       * Example test:
9896       *
9897       * ```js
9898       *  it('should behave like a cache', inject(function(superCache) {
9899       *    superCache.put('key', 'value');
9900       *    superCache.put('another key', 'another value');
9901       *
9902       *    expect(superCache.info()).toEqual({
9903       *      id: 'super-cache',
9904       *      size: 2
9905       *    });
9906       *
9907       *    superCache.remove('another key');
9908       *    expect(superCache.get('another key')).toBeUndefined();
9909       *
9910       *    superCache.removeAll();
9911       *    expect(superCache.info()).toEqual({
9912       *      id: 'super-cache',
9913       *      size: 0
9914       *    });
9915       *  }));
9916       * ```
9917       */
9918      return caches[cacheId] = {
9919
9920        /**
9921         * @ngdoc method
9922         * @name $cacheFactory.Cache#put
9923         * @kind function
9924         *
9925         * @description
9926         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
9927         * retrieved later, and incrementing the size of the cache if the key was not already
9928         * present in the cache. If behaving like an LRU cache, it will also remove stale
9929         * entries from the set.
9930         *
9931         * It will not insert undefined values into the cache.
9932         *
9933         * @param {string} key the key under which the cached data is stored.
9934         * @param {*} value the value to store alongside the key. If it is undefined, the key
9935         *    will not be stored.
9936         * @returns {*} the value stored.
9937         */
9938        put: function(key, value) {
9939          if (capacity < Number.MAX_VALUE) {
9940            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
9941
9942            refresh(lruEntry);
9943          }
9944
9945          if (isUndefined(value)) return;
9946          if (!(key in data)) size++;
9947          data[key] = value;
9948
9949          if (size > capacity) {
9950            this.remove(staleEnd.key);
9951          }
9952
9953          return value;
9954        },
9955
9956        /**
9957         * @ngdoc method
9958         * @name $cacheFactory.Cache#get
9959         * @kind function
9960         *
9961         * @description
9962         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
9963         *
9964         * @param {string} key the key of the data to be retrieved
9965         * @returns {*} the value stored.
9966         */
9967        get: function(key) {
9968          if (capacity < Number.MAX_VALUE) {
9969            var lruEntry = lruHash[key];
9970
9971            if (!lruEntry) return;
9972
9973            refresh(lruEntry);
9974          }
9975
9976          return data[key];
9977        },
9978
9979
9980        /**
9981         * @ngdoc method
9982         * @name $cacheFactory.Cache#remove
9983         * @kind function
9984         *
9985         * @description
9986         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
9987         *
9988         * @param {string} key the key of the entry to be removed
9989         */
9990        remove: function(key) {
9991          if (capacity < Number.MAX_VALUE) {
9992            var lruEntry = lruHash[key];
9993
9994            if (!lruEntry) return;
9995
9996            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
9997            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
9998            link(lruEntry.n,lruEntry.p);
9999
10000            delete lruHash[key];
10001          }
10002
10003          delete data[key];
10004          size--;
10005        },
10006
10007
10008        /**
10009         * @ngdoc method
10010         * @name $cacheFactory.Cache#removeAll
10011         * @kind function
10012         *
10013         * @description
10014         * Clears the cache object of any entries.
10015         */
10016        removeAll: function() {
10017          data = {};
10018          size = 0;
10019          lruHash = {};
10020          freshEnd = staleEnd = null;
10021        },
10022
10023
10024        /**
10025         * @ngdoc method
10026         * @name $cacheFactory.Cache#destroy
10027         * @kind function
10028         *
10029         * @description
10030         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
10031         * removing it from the {@link $cacheFactory $cacheFactory} set.
10032         */
10033        destroy: function() {
10034          data = null;
10035          stats = null;
10036          lruHash = null;
10037          delete caches[cacheId];
10038        },
10039
10040
10041        /**
10042         * @ngdoc method
10043         * @name $cacheFactory.Cache#info
10044         * @kind function
10045         *
10046         * @description
10047         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
10048         *
10049         * @returns {object} an object with the following properties:
10050         *   <ul>
10051         *     <li>**id**: the id of the cache instance</li>
10052         *     <li>**size**: the number of entries kept in the cache instance</li>
10053         *     <li>**...**: any additional properties from the options object when creating the
10054         *       cache.</li>
10055         *   </ul>
10056         */
10057        info: function() {
10058          return extend({}, stats, {size: size});
10059        }
10060      };
10061
10062
10063      /**
10064       * makes the `entry` the freshEnd of the LRU linked list
10065       */
10066      function refresh(entry) {
10067        if (entry != freshEnd) {
10068          if (!staleEnd) {
10069            staleEnd = entry;
10070          } else if (staleEnd == entry) {
10071            staleEnd = entry.n;
vendor: 4,905 bytes, lines 10072-10235
10072          }
10073
10074          link(entry.n, entry.p);
10075          link(entry, freshEnd);
10076          freshEnd = entry;
10077          freshEnd.n = null;
10078        }
10079      }
10080
10081
10082      /**
10083       * bidirectionally links two entries of the LRU linked list
10084       */
10085      function link(nextEntry, prevEntry) {
10086        if (nextEntry != prevEntry) {
10087          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
10088          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
10089        }
10090      }
10091    }
10092
10093
10094  /**
10095   * @ngdoc method
10096   * @name $cacheFactory#info
10097   *
10098   * @description
10099   * Get information about all the caches that have been created
10100   *
10101   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
10102   */
10103    cacheFactory.info = function() {
10104      var info = {};
10105      forEach(caches, function(cache, cacheId) {
10106        info[cacheId] = cache.info();
10107      });
10108      return info;
10109    };
10110
10111
10112  /**
10113   * @ngdoc method
10114   * @name $cacheFactory#get
10115   *
10116   * @description
10117   * Get access to a cache object by the `cacheId` used when it was created.
10118   *
10119   * @param {string} cacheId Name or id of a cache to access.
10120   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
10121   */
10122    cacheFactory.get = function(cacheId) {
10123      return caches[cacheId];
10124    };
10125
10126
10127    return cacheFactory;
10128  };
10129}
10130
10131/**
10132 * @ngdoc service
10133 * @name $templateCache
10134 *
10135 * @description
10136 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
10137 * can load templates directly into the cache in a `script` tag, or by consuming the
10138 * `$templateCache` service directly.
10139 *
10140 * Adding via the `script` tag:
10141 *
10142 * ```html
10143 *   <script type="text/ng-template" id="templateId.html">
10144 *     <p>This is the content of the template</p>
10145 *   </script>
10146 * ```
10147 *
10148 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
10149 * the document, but it must be below the `ng-app` definition.
10150 *
10151 * Adding via the $templateCache service:
10152 *
10153 * ```js
10154 * var myApp = angular.module('myApp', []);
10155 * myApp.run(function($templateCache) {
10156 *   $templateCache.put('templateId.html', 'This is the content of the template');
10157 * });
10158 * ```
10159 *
10160 * To retrieve the template later, simply use it in your HTML:
10161 * ```html
10162 * <div ng-include=" 'templateId.html' "></div>
10163 * ```
10164 *
10165 * or get it via Javascript:
10166 * ```js
10167 * $templateCache.get('templateId.html')
10168 * ```
10169 *
10170 * See {@link ng.$cacheFactory $cacheFactory}.
10171 *
10172 */
10173function $TemplateCacheProvider() {
10174  this.$get = ['$cacheFactory', function($cacheFactory) {
10175    return $cacheFactory('templates');
10176  }];
10177}
10178
10179/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
10180 *
10181 * DOM-related variables:
10182 *
10183 * - "node" - DOM Node
10184 * - "element" - DOM Element or Node
10185 * - "$node" or "$element" - jqLite-wrapped node or element
10186 *
10187 *
10188 * Compiler related stuff:
10189 *
10190 * - "linkFn" - linking fn of a single directive
10191 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
10192 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
10193 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
10194 */
10195
10196
10197/**
10198 * @ngdoc service
10199 * @name $compile
10200 * @kind function
10201 *
10202 * @description
10203 * Compiles an HTML string or DOM into a template and produces a template function, which
10204 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
10205 *
10206 * The compilation is a process of walking the DOM tree and matching DOM elements to
10207 * {@link ng.$compileProvider#directive directives}.
10208 *
10209 * <div class="alert alert-warning">
10210 * **Note:** This document is an in-depth reference of all directive options.
10211 * For a gentle introduction to directives with examples of common use cases,
10212 * see the {@link guide/directive directive guide}.
10213 * </div>
10214 *
10215 * ## Comprehensive Directive API
10216 *
10217 * There are many different options for a directive.
10218 *
10219 * The difference resides in the return value of the factory function.
10220 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
10221 * or just the `postLink` function (all other properties will have the default values).
10222 *
10223 * <div class="alert alert-success">
10224 * **Best Practice:** It's recommended to use the "directive definition object" form.
10225 * </div>
10226 *
10227 * Here's an example directive declared with a Directive Definition Object:
10228 *
10229 * ```js
10230 *   var myModule = angular.module(...);
10231 *
10232 *   myModule.directive('directiveName', function factory(injectables) {
10233 *     var directiveDefinitionObject = {
10234 *       priority: 0,
10235 *       template: '<div></div>
10235', // or // function(tElement, tAttrs) { ... },
10236 *       // or
10237 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
10238 *       transclude: false,
10239 *       restrict: 'A',
10240 *       scope: false,
10241 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
10242 *       controllerAs: 'stringAlias',
10243 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
10244 *       compile: function compile(tElement, tAttrs, transclude) {
10245 *         return {
10246 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
10247 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
10248 *         }
10249 *         // or
10250 *         // return function postLink( ... ) { ... }
10251 *       },
10252 *       // or
10253 *       // link: {
10254 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
10255 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
10256 *       // }
10257 *       // or
10258 *       // link: function postLink( ... ) { ... }
10259 *     };
10260 *     return directiveDefinitionObject;
10261 *   });
10262 * ```
10263 *
10264 * <div class="alert alert-warning">
10265 * **Note:** Any unspecified options will use the default value. You can see the default values below.
10266 * </div>
10267 *
10268 * Therefore the above can be simplified as:
10269 *
10270 * ```js
10271 *   var myModule = angular.module(...);
10272 *
10273 *   myModule.directive('directiveName', function factory(injectables) {
10274 *     var directiveDefinitionObject = {
10275 *       link: function postLink(scope, iElement, iAttrs) { ... }
10276 *     };
10277 *     return directiveDefinitionObject;
10278 *     // or
10279 *     // return function postLink(scope, iElement, iAttrs) { ... }
10280 *   });
10281 * ```
10282 *
10283 *
10284 *
10285 * ### Directive Definition Object
10286 *
10287 * The directive definition object provides instructions to the {@link ng.$compile
10288 * compiler}. The attributes are:
10289 *
10290 * #### `priority`
10291 * When there are multiple directives defined on a single DOM element, sometimes it
10292 * is necessary to specify the order in which the directives are applied. The `priority` is used
10293 * to sort the directives before their `compile` functions get called. Priority is defined as a
10294 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
10295 * are also run in priority order, but post-link functions are run in reverse order. The order
10296 * of directives with the same priority is undefined. The default priority is `0`.
10297 *
10298 * #### `terminal`
10299 * If set to true then the current `priority` will be the last set of directives
10300 * which will execute (any directives at the current priority will still execute
10301 * as the order of execution on same `priority` is undefined).
10302 *
10303 * #### `scope`
10304 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
10305 * same element request a new scope, only one new scope is created. The new scope rule does not
10306 * apply for the root of the template since the root of the template always gets a new scope.
10307 *
10308 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
10309 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
10310 * when creating reusable components, which should not accidentally read or modify data in the
10311 * parent scope.
10312 *
10313 * The 'isolate' scope takes an object hash which defines a set of local scope properties
10314 * derived from the parent scope. These local properties are useful for aliasing values for
10315 * templates. Locals definition is a hash of local scope property to its source:
10316 *
10317 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
10318 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
10319 *   attribute name is assumed to be the same as the local name.
10320 *   Given `<widget my-attr="hello {{name}}">` and widget definition
10321 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
10322 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
10323 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
10324 *   component scope).
10325 *
10326 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
10327 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
10328 *   name is specified then the attribute name is assumed to be the same as the local name.
10329 *   Given `<widget my-attr="parentModel">` and widget definition of
10330 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
10331 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
10332 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
10333 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
10334 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
10335 *
10336 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
10337 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
10338 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
10339 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
10340 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
10341 *   pass data from the isolated scope via an expression to the parent scope, this can be
10342 *   done by passing a map of local variable names and values into the expression wrapper fn.
10343 *   For example, if the expression is `increment(amount)` then we can specify the amount value
10344 *   by calling the `localFn` as `localFn({amount: 22})`.
10345 *
10346 *
10347 *
10348 * #### `controller`
10349 * Controller constructor function. The controller is instantiated before the
10350 * pre-linking phase and it is shared with other directives (see
10351 * `require` attribute). This allows the directives to communicate with each other and augment
10352 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
10353 *
10354 * * `$scope` - Current scope associated with the element
10355 * * `$element` - Current element
10356 * * `$attrs` - Current attributes object for the element
10357 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
10358 *    The scope can be overridden by an optional first argument.
10359 *   `function([scope], cloneLinkingFn)`.
10360 *
10361 *
10362 * #### `require`
10363 * Require another directive and inject its controller as the fourth argument to the linking function. The
10364 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
10365 * injected argument will be an array in corresponding order. If no such directive can be
10366 * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
10367 *
10368 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
10369 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
10370 * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
10371 * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
10372 *   `null` to the `link` fn if not found.
10373 *
10374 *
10375 * #### `controllerAs`
10376 * Controller alias at the directive scope. An alias for the controller so it
10377 * can be referenced at the directive template. The directive needs to define a scope for this
10378 * configuration to be used. Useful in the case when directive is used as component.
10379 *
10380 *
10381 * #### `restrict`
10382 * String of subset of `EACM` which restricts the directive to a specific directive
10383 * declaration style. If omitted, the default (attributes only) is used.
10384 *
10385 * * `E` - Element name: `<my-directive></my-directive>`
10386 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
10387 * * `C` - Class: `<div class="my-directive: exp;"></div>`
10388 * * `M` - Comment: `<!-- directive: my-directive exp -->`
10389 *
10390 *
10391 * #### `template`
10392 * HTML markup that may:
10393 * * Replace the contents of the directive's element (default).
10394 * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
10395 * * Wrap the contents of the directive's element (if `transclude` is true).
10396 *
10397 * Value may be:
10398 *
10399 * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
10400 * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
10401 *   function api below) and returns a string value.
10402 *
10403 *
10404 * #### `templateUrl`
10405 * Same as `template` but the template is loaded from the specified URL. Because
10406 * the template loading is asynchronous the compilation/linking is suspended until the template
10407 * is loaded.
10408 *
10409 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
10410 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
10411 * a string value representing the url.  In either case, the template URL is passed through {@link
10412 * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
10413 *
10414 *
10415 * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
10416 * specify what the template should replace. Defaults to `false`.
10417 *
10418 * * `true` - the template will replace the directive's element.
10419 * * `false` - the template will replace the contents of the directive's element.
10420 *
10421 * The replacement process migrates all of the attributes / classes from the old element to the new
10422 * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
10423 * Directives Guide} for an example.
10424 *
10425 * #### `transclude`
10426 * compile the content of the element and make it available to the directive.
10427 * Typically used with {@link ng.directive:ngTransclude
10428 * ngTransclude}. The advantage of transclusion is that the linking function receives a
10429 * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
10430 * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
10431 * scope. This makes it possible for the widget to have private state, and the transclusion to
10432 * be bound to the parent (pre-`isolate`) scope.
10433 *
10434 * * `true` - transclude the content of the directive.
10435 * * `'element'` - transclude the whole element including any directives defined at lower priority.
10436 *
10437 * <div class="alert alert-warning">
10438 * **Note:** When testing an element transclude directive you must not place the directive at the root of the
10439 * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
10440 * Testing Transclusion Directives}.
10441 * </div>
10442 *
10443 * #### `compile`
10444 *
10445 * ```js
10446 *   function compile(tElement, tAttrs, transclude) { ... }
10447 * ```
10448 *
10449 * The compile function deals with transforming the template DOM. Since most directives do not do
10450 * template transformation, it is not used often. The compile function takes the following arguments:
10451 *
10452 *   * `tElement` - template element - The element where the directive has been declared. It is
10453 *     safe to do template transformation on the element and child elements only.
10454 *
10455 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
10456 *     between all directive compile functions.
10457 *
10458 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
10459 *
10460 * <div class="alert alert-warning">
10461 * **Note:** The template instance and the link instance may be different objects if the template has
10462 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
10463 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
10464 * should be done in a linking function rather than in a compile function.
10465 * </div>
10466
10467 * <div class="alert alert-warning">
10468 * **Note:** The compile function cannot handle directives that recursively use themselves in their
10469 * own templates or compile functions. Compiling these directives results in an infinite loop and a
10470 * stack overflow errors.
10471 *
10472 * This can be avoided by manually using $compile in the postLink function to imperatively compile
10473 * a directive's template instead of relying on automatic template compilation via `template` or
10474 * `templateUrl` declaration or manual compilation inside the compile function.
10475 * </div>
10476 *
10477 * <div class="alert alert-error">
10478 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
10479 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
10480 *   to the link function instead.
10481 * </div>
10482
10483 * A compile function can have a return value which can be either a function or an object.
10484 *
10485 * * returning a (post-link) function - is equivalent to registering the linking function via the
10486 *   `link` property of the config object when the compile function is empty.
10487 *
10488 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
10489 *   control when a linking function should be called during the linking phase. See info about
10490 *   pre-linking and post-linking functions below.
10491 *
10492 *
10493 * #### `link`
10494 * This property is used only if the `compile` property is not defined.
10495 *
10496 * ```js
10497 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
10498 * ```
10499 *
10500 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
10501 * executed after the template has been cloned. This is where most of the directive logic will be
10502 * put.
10503 *
10504 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
10505 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
10506 *
10507 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
10508 *     manipulate the children of the element only in `postLink` function since the children have
10509 *     already been linked.
10510 *
10511 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
10512 *     between all directive linking functions.
10513 *
10514 *   * `controller` - a controller instance - A controller instance if at least one directive on the
10515 *     element defines a controller. The controller is shared among all the directives, which allows
10516 *     the directives to use the controllers as a communication channel.
10517 *
10518 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
10519 *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
10520 *     parameter of directive controllers.
10521 *     `function([scope], cloneLinkingFn)`.
10522 *
10523 *
10524 * #### Pre-linking function
10525 *
10526 * Executed before the child elements are linked. Not safe to do DOM transformation since the
10527 * compiler linking function will fail to locate the correct elements for linking.
10528 *
10529 * #### Post-linking function
10530 *
10531 * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
10532 *
10533 * <a name="Attributes"></a>
10534 * ### Attributes
10535 *
10536 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
10537 * `link()` or `compile()` functions. It has a variety of uses.
10538 *
10539 * accessing *Normalized attribute names:*
10540 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
10541 * the attributes object allows for normalized access to
10542 *   the attributes.
10543 *
10544 * * *Directive inter-communication:* All directives share the same instance of the attributes
10545 *   object which allows the directives to use the attributes object as inter directive
10546 *   communication.
10547 *
10548 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
10549 *   allowing other directives to read the interpolated value.
10550 *
10551 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
10552 *   that contain interpolation (e.g. `src="{{bar}}
10552"`). Not only is this very efficient but it's also
10553 *   the only way to easily get the actual value because during the linking phase the interpolation
10554 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
10555 *
10556 * ```js
10557 * function linkingFn(scope, elm, attrs, ctrl) {
10558 *   // get the attribute value
10559 *   console.log(attrs.ngModel);
10560 *
10561 *   // change the attribute
10562 *   attrs.$set('ngModel', 'new value');
10563 *
10564 *   // observe changes to interpolated attribute
10565 *   attrs.$observe('ngModel', function(value) {
10566 *     console.log('ngModel has changed value to ' + value);
10567 *   });
10568 * }
10569 * ```
10570 *
10571 * Below is an example using `$compileProvider`.
10572 *
10573 * <div class="alert alert-warning">
10574 * **Note**: Typically directives are registered with `module.directive`. The example below is
10575 * to illustrate how `$compile` works.
10576 * </div>
10577 *
10578 <example module="compileExample">
10579   <file name="index.html">
10580    <script>
10581      angular.module('compileExample', [], function($compileProvider) {
10582        // configure new 'compile' directive by passing a directive
10583        // factory function. The factory function injects the '$compile'
10584        $compileProvider.directive('compile', function($compile) {
10585          // directive factory creates a link function
10586          return function(scope, element, attrs) {
10587            scope.$watch(
10588              function(scope) {
10589                 // watch the 'compile' expression for changes
10590                return scope.$eval(attrs.compile);
10591              },
10592              function(value) {
10593                // when the 'compile' expression changes
10594                // assign it into the current DOM
10595                element.html(value);
10596
10597                // compile the new DOM and link it to the current
10598                // scope.
10599                // NOTE: we only compile .childNodes so that
10600                // we don't get into infinite loop compiling ourselves
10601                $compile(element.contents())(scope);
10602              }
10603            );
10604          };
10605        });
10606      })
10607      .controller('GreeterController', ['$scope', function($scope) {
10608        $scope.name = 'Angular';
10609        $scope.html = 'Hello {{name}}';
10610      }]);
10611    </script>
10612    <div ng-controller="GreeterController">
10613      <input ng-model="name"> <br>
10614      <textarea ng-model="html"></textarea> <br>
10615      <div compile="html"></div>
10616    </div>
10617   </file>
10618   <file name="protractor.js" type="protractor">
10619     it('should auto compile', function() {
10620       var textarea = $('textarea');
10621       var output = $('div[compile]');
10622       // The initial state reads 'Hello Angular'.
10623       expect(output.getText()).toBe('Hello Angular');
10624       textarea.clear();
10625       textarea.sendKeys('{{name}}!');
10626       expect(output.getText()).toBe('Angular!');
10627     });
10628   </file>
10629 </example>
10630
10631 *
10632 *
10633 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
10634 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
10635 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
10636 *                 root element(s), not their children)
10637 * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
10638 * (a DOM element/tree) to a scope. Where:
10639 *
10640 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
10641 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
10642 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
10643 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
10644 *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
10645 *
10646 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
10647 *      * `scope` - is the current scope with which the linking function is working with.
10648 *
10649 * Calling the linking function returns the element of the template. It is either the original
10650 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
10651 *
10652 * After linking the view is not updated until after a call to $digest which typically is done by
10653 * Angular automatically.
10654 *
10655 * If you need access to the bound view, there are two ways to do it:
10656 *
10657 * - If you are not asking the linking function to clone the template, create the DOM element(s)
10658 *   before you send them to the compiler and keep this reference around.
10659 *   ```js
10660 *     var element = $compile('<p>{{total}}</p>')(scope);
10661 *   ```
10662 *
10663 * - if on the other hand, you need the element to be cloned, the view reference from the original
10664 *   example would not point to the clone, but rather to the original template that was cloned. In
10665 *   this case, you can access the clone via the cloneAttachFn:
10666 *   ```js
10667 *     var templateElement = angular.element('<p>{{total}}</p>'),
10668 *         scope = ....;
10669 *
10670 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
10671 *       //attach the clone to DOM document at the right place
10672 *     });
10673 *
10674 *     //now we have reference to the cloned DOM via `clonedElement`
10675 *   ```
10676 *
10677 *
10678 * For information on how the compiler works, see the
10679 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
10680 */
10681
10682var $compileMinErr = minErr('$compile');
10683
10684/**
10685 * @ngdoc provider
10686 * @name $compileProvider
10687 * @kind function
10688 *
10689 * @description
10690 */
10691$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
10692function $CompileProvider($provide, $$sanitizeUriProvider) {
10693  var hasDirectives = {},
10694      Suffix = 'Directive',
10695      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
10696      CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
10697
10698  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
10699  // The assumption is that future DOM event attribute names will begin with
10700  // 'on' and be composed of only English letters.
10701  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
10702
10703  /**
10704   * @ngdoc method
10705   * @name $compileProvider#directive
10706   * @kind function
10707   *
10708   * @description
10709   * Register a new directive with the compiler.
10710   *
10711   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
10712   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
10713   *    names and the values are the factories.
10714   * @param {Function|Array} directiveFactory An injectable directive factory function. See
10715   *    {@link guide/directive} for more info.
10716   * @returns {ng.$compileProvider} Self for chaining.
10717   */
10718   this.directive = function registerDirective(name, directiveFactory) {
10719    assertNotHasOwnProperty(name, 'directive');
10720    if (isString(name)) {
10721      assertArg(directiveFactory, 'directiveFactory');
10722      if (!hasDirectives.hasOwnProperty(name)) {
10723        hasDirectives[name] = [];
10724        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
10725          function($injector, $exceptionHandler) {
10726            var directives = [];
10727            forEach(hasDirectives[name], function(directiveFactory, index) {
10728              try {
10729                var directive = $injector.invoke(directiveFactory);
10730                if (isFunction(directive)) {
10731                  directive = { compile: valueFn(directive) };
10732                } else if (!directive.compile && directive.link) {
10733                  directive.compile = valueFn(directive.link);
10734                }
10735                directive.priority = directive.priority || 0;
10736                directive.index = index;
10737                directive.name = directive.name || name;
10738                directive.require = directive.require || (directive.controller && directive.name);
10739                directive.restrict = directive.restrict || 'A';
10740                directives.push(directive);
10741              } catch (e) {
10742                $exceptionHandler(e);
10743              }
10744            });
10745            return directives;
10746          }]);
10747      }
10748      hasDirectives[name].push(directiveFactory);
10749    } else {
10750      forEach(name, reverseParams(registerDirective));
10751    }
10752    return this;
10753  };
10754
10755
10756  /**
10757   * @ngdoc method
10758   * @name $compileProvider#aHrefSanitizationWhitelist
10759   * @kind function
10760   *
10761   * @description
10762   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
10763   * urls during a[href] sanitization.
10764   *
10765   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
10766   *
10767   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
10768   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
10769   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
10770   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
10771   *
10772   * @param {RegExp=} regexp New regexp to whitelist urls with.
10773   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
10774   *    chaining otherwise.
10775   */
10776  this.aHrefSanitizationWhitelist = function(regexp) {
10777    if (isDefined(regexp)) {
10778      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
10779      return this;
10780    } else {
10781      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
10782    }
10783  };
10784
10785
10786  /**
10787   * @ngdoc method
10788   * @name $compileProvider#imgSrcSanitizationWhitelist
10789   * @kind function
10790   *
10791   * @description
10792   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
10793   * urls during img[src] sanitization.
10794   *
10795   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
10796   *
10797   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
10798   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
10799   * regular expression. If a match is found, the original url is 
10799written into the dom. Otherwise,
10800   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
10801   *
10802   * @param {RegExp=} regexp New regexp to whitelist urls with.
10803   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
10804   *    chaining otherwise.
10805   */
10806  this.imgSrcSanitizationWhitelist = function(regexp) {
10807    if (isDefined(regexp)) {
10808      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
10809      return this;
10810    } else {
10811      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
10812    }
10813  };
10814
10815  this.$get = [
10816            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
10817            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
10818    function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
10819             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
10820
10821    var Attributes = function(element, attr) {
10822      this.$$element = element;
10823      this.$attr = attr || {};
10824    };
10825
10826    Attributes.prototype = {
10827      $normalize: directiveNormalize,
10828
10829
10830      /**
10831       * @ngdoc method
10832       * @name $compile.directive.Attributes#$addClass
10833       * @kind function
10834       *
10835       * @description
10836       * Adds the CSS class value specified by the classVal parameter to the element. If animations
10837       * are enabled then an animation will be triggered for the class addition.
10838       *
10839       * @param {string} classVal The className value that will be added to the element
10840       */
10841      $addClass : function(classVal) {
10842        if(classVal && classVal.length > 0) {
10843          $animate.addClass(this.$$element, classVal);
10844        }
10845      },
10846
10847      /**
10848       * @ngdoc method
10849       * @name $compile.directive.Attributes#$removeClass
10850       * @kind function
10851       *
10852       * @description
10853       * Removes the CSS class value specified by the classVal parameter from the element. If
10854       * animations are enabled then an animation will be triggered for the class removal.
10855       *
10856       * @param {string} classVal The className value that will be removed from the element
10857       */
10858      $removeClass : function(classVal) {
10859        if(classVal && classVal.length > 0) {
10860          $animate.removeClass(this.$$element, classVal);
10861        }
10862      },
10863
10864      /**
10865       * @ngdoc method
10866       * @name $compile.directive.Attributes#$updateClass
10867       * @kind function
10868       *
10869       * @description
10870       * Adds and removes the appropriate CSS class values to the element based on the difference
10871       * between the new and old CSS class values (specified as newClasses and oldClasses).
10872       *
10873       * @param {string} newClasses The current CSS className value
10874       * @param {string} oldClasses The former CSS className value
10875       */
10876      $updateClass : function(newClasses, oldClasses) {
10877        var toAdd = tokenDifference(newClasses, oldClasses);
10878        var toRemove = tokenDifference(oldClasses, newClasses);
10879
10880        if(toAdd.length === 0) {
10881          $animate.removeClass(this.$$element, toRemove);
10882        } else if(toRemove.length === 0) {
10883          $animate.addClass(this.$$element, toAdd);
10884        } else {
10885          $animate.setClass(this.$$element, toAdd, toRemove);
10886        }
10887      },
10888
10889      /**
10890       * Set a normalized attribute on the element in a way such that all directives
10891       * can share the attribute. This function properly handles boolean attributes.
10892       * @param {string} key Normalized key. (ie ngAttribute)
10893       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
10894       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
10895       *     Defaults to true.
10896       * @param {string=} attrName Optional none normalized name. Defaults to key.
10897       */
10898      $set: function(key, value, writeAttr, attrName) {
10899        // TODO: decide whether or not to throw an error if "class"
10900        //is set through this function since it may cause $updateClass to
10901        //become unstable.
10902
10903        var booleanKey = getBooleanAttrName(this.$$element[0], key),
10904            normalizedVal,
10905            nodeName;
10906
10907        if (booleanKey) {
10908          this.$$element.prop(key, value);
10909          attrName = booleanKey;
10910        }
10911
10912        this[key] = value;
10913
10914        // translate normalized key to actual key
10915        if (attrName) {
10916          this.$attr[key] = attrName;
10917        } else {
10918          attrName = this.$attr[key];
10919          if (!attrName) {
10920            this.$attr[key] = attrName = snake_case(key, '-');
10921          }
10922        }
10923
10924        nodeName = nodeName_(this.$$element);
10925
10926        // sanitize a[href] and img[src] values
10927        if ((nodeName === 'A' && key === 'href') ||
10928            (nodeName === 'IMG' && key === 'src')) {
10929          this[key] = value = $$sanitizeUri(value, key === 'src');
10930        }
10931
10932        if (writeAttr !== false) {
10933          if (value === null || value === undefined) {
10934            this.$$element.removeAttr(attrName);
10935          } else {
10936            this.$$element.attr(attrName, value);
10937          }
10938        }
10939
10940        // fire observers
10941        var $$observers = this.$$observers;
10942        $$observers && forEach($$observers[key], function(fn) {
10943          try {
10944            fn(value);
10945          } catch (e) {
10946            $exceptionHandler(e);
10947          }
10948        });
10949      },
10950
10951
10952      /**
10953       * @ngdoc method
10954       * @name $compile.directive.Attributes#$observe
10955       * @kind function
10956       *
10957       * @description
10958       * Observes an interpolated attribute.
10959       *
10960       * The observer function will be invoked once during the next `$digest` following
10961       * compilation. The observer is then invoked whenever the interpolated value
10962       * changes.
10963       *
10964       * @param {string} key Normalized key. (ie ngAttribute) .
10965       * @param {function(interpolatedValue)} fn Function that will be called whenever
10966                the interpolated value of the attribute changes.
10967       *        See the {@link guide/directive#Attributes Directives} guide for more info.
10968       * @returns {function()} the `fn` parameter.
10969       */
10970      $observe: function(key, fn) {
10971        var attrs = this,
10972            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
10973            listeners = ($$observers[key] || ($$observers[key] = []));
10974
10975        listeners.push(fn);
10976        $rootScope.$evalAsync(function() {
10977          if (!listeners.$$inter) {
10978            // no one registered attribute interpolation function, so lets call it manually
10979            fn(attrs[key]);
10980          }
10981        });
10982        return fn;
10983      }
10984    };
10985
10986    var startSymbol = $interpolate.startSymbol(),
10987        endSymbol = $interpolate.endSymbol(),
10988        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
10989            ? identity
10990            : function denormalizeTemplate(template) {
10991              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
10992        },
10993        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
10994
10995
10996    return compile;
10997
10998    //================================
10999
11000    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
11001                        previousCompileContext) {
11002      if (!($compileNodes instanceof jqLite)) {
11003        // jquery always rewraps, whereas we need to preserve the original selector so that we can
11004        // modify it.
11005        $compileNodes = jqLite($compileNodes);
11006      }
11007      // We can not compile top level text elements since text nodes can be merged and we will
11008      // not be able to attach scope data to them, so we will wrap them in <span>
11009      forEach($compileNodes, function(node, index){
11010        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
11011          $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
11012        }
11013      });
11014      var compositeLinkFn =
11015              compileNodes($compileNodes, transcludeFn, $compileNodes,
11016                           maxPriority, ignoreDirective, previousCompileContext);
11017      safeAddClass($compileNodes, 'ng-scope');
11018      return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){
11019        assertArg(scope, 'scope');
11020        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
11021        // and sometimes changes the structure of the DOM.
11022        var $linkNode = cloneConnectFn
11023          ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
11024          : $compileNodes;
11025
11026        forEach(transcludeControllers, function(instance, name) {
11027          $linkNode.data('$' + name + 'Controller', instance);
11028        });
11029
11030        // Attach scope only to non-text nodes.
11031        for(var i = 0, ii = $linkNode.length; i<ii; i++) {
11032          var node = $linkNode[i],
11033              nodeType = node.nodeType;
11034          if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
11035            $linkNode.eq(i).data('$scope', scope);
11036          }
11037        }
11038
11039        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
11040        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
11041        return $linkNode;
11042      };
11043    }
11044
11045    function safeAddClass($element, className) {
11046      try {
11047        $element.addClass(className);
11048      } catch(e) {
11049        // ignore, since it means that we are trying to set class on
11050        // SVG element, where class name is read-only.
11051      }
11052    }
11053
11054    /**
11055     * Compile function matches each node in nodeList against the directives. Once all directives
11056     * for a particular node are collected their compile functions are executed. The compile
11057     * functions return values - the linking functions - are combined into a composite linking
11058     * function, which is the a linking function for the node.
11059     *
11060     * @param {NodeList} nodeList an array of nodes or NodeList to compile
11061     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
11062     *        scope argument is auto-generated to the new child of the transcluded parent scope.
11063     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
11064     *        the rootElement must be set the jqLite collection of the compile root. This is
11065     *        needed so that the jqLite collection items can be replaced with widgets.
11066     * @param {number=} maxPriority Max directive priority.
11067     * @returns {Function} A composite linking function of all of the matched directives or null.
11068     */
11069    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
11070                            previousCompileContext) {
11071      var linkFns = [],
11072          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
11073
11074      for (var i = 0; i < nodeList.length; i++) {
11075        attrs = new Attributes();
11076
11077        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
11078        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
11079                                        ignoreDirective);
11080
11081        nodeLinkFn = (directives.length)
11082            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
11083                                      null, [], [], previousCompileContext)
11084            : null;
11085
11086        if (nodeLinkFn && nodeLinkFn.scope) {
11087          safeAddClass(attrs.$$element, 'ng-scope');
11088        }
11089
11090        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
11091                      !(childNodes = nodeList[i].childNodes) ||
11092                      !childNodes.length)
11093            ? null
11094            : compileNodes(childNodes,
11095                 nodeLinkFn ? (
11096                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
11097                     && nodeLinkFn.transclude) : transcludeFn);
11098
11099        linkFns.push(nodeLinkFn, childLinkFn);
11100        linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
11101        //use the previous context only for the first element in the virtual group
11102        previousCompileContext = null;
11103      }
11104
11105      // return a linking function if we have found anything, null otherwise
11106      return linkFnFound ? compositeLinkFn : null;
11107
11108      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
11109        var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
11110
11111        // copy nodeList so that linking doesn't break due to live list updates.
11112        var nodeListLength = nodeList.length,
11113            stableNodeList = new Array(nodeListLength);
11114        for (i = 0; i < nodeListLength; i++) {
11115          stableNodeList[i] = nodeList[i];
11116        }
11117
11118        for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
11119          node = stableNodeList[n];
11120          nodeLinkFn = linkFns[i++];
11121          childLinkFn = linkFns[i++];
11122
11123          if (nodeLinkFn) {
11124            if (nodeLinkFn.scope) {
11125              childScope = scope.$new();
11126              jqLite.data(node, '$scope', childScope);
11127            } else {
11128              childScope = scope;
11129            }
11130
11131            if ( nodeLinkFn.transcludeOnThisElement ) {
11132              childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
11133
11134            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
11135              childBoundTranscludeFn = parentBoundTranscludeFn;
11136
11137            } else if (!parentBoundTranscludeFn && transcludeFn) {
11138              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
11139
11140            } else {
11141              childBoundTranscludeFn = null;
11142            }
11143
11144            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
11145
11146          } else if (childLinkFn) {
11147            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
11148          }
11149        }
11150      }
11151    }
11152
11153    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
11154
11155      var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) {
11156        var scopeCreated = false;
11157
11158        if (!transcludedScope) {
11159          transcludedScope = scope.$new();
11160          transcludedScope.$$transcluded = true;
11161          scopeCreated = true;
11162        }
11163
11164        var clone = transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn);
11165        if (scopeCreated) {
11166          clone.on('$destroy', function() { transcludedScope.$destroy(); });
11167        }
11168        return clone;
11169      };
11170
11171      return boundTranscludeFn;
11172    }
11173
11174    /**
11175     * Looks for directives on the given node and adds them to the directive collection which is
11176     * sorted.
11177     *
11178     * @param node Node to search.
11179     * @param directives An array to which the directives are added to. This array is sorted before
11180     *        the function returns.
11181     * @param attrs The shared attrs object which is used to populate the normalized attributes.
11182     * @param {number=} maxPriority Max directive priority.
11183     */
11184    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
11185      var nodeType = node.nodeType,
11186          attrsMap = attrs.$attr,
11187          match,
11188          className;
11189
11190      switch(nodeType) {
11191        case 1: /* Element */
11192          // use the node name: <directive>
11193          addDirective(directives,
11194              directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
11195
11196          // iterate over the attributes
11197          for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
11198                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
11199            var attrStartName = false;
11200            var attrEndName = false;
11201
11202            attr = nAttrs[j];
11203            if (!msie || msie >= 8 || attr.specified) {
11204              name = attr.name;
11205              value = trim(attr.value);
11206
11207              // support ngAttr attribute binding
11208              ngAttrName = directiveNormalize(name);
11209              if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
11210                name = snake_case(ngAttrName.substr(6), '-');
11211              }
11212
11213              var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
11214              if (ngAttrName === directiveNName + 'Start') {
11215                attrStartName = name;
11216                attrEndName = name.substr(0, name.length - 5) + 'end';
11217                name = name.substr(0, name.length - 6);
11218              }
11219
11220              nName = directiveNormalize(name.toLowerCase());
11221              attrsMap[nName] = name;
11222              if (isNgAttr || !attrs.hasOwnProperty(nName)) {
11223                  attrs[nName] = value;
11224                  if (getBooleanAttrName(node, nName)) {
11225                    attrs[nName] = true; // presence means true
11226                  }
11227              }
11228              addAttrInterpolateDirective(node, directives, value, nName);
11229              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
11230                            attrEndName);
11231            }
11232          }
11233
11234          // use class as directive
11235          className = node.className;
11236          if (isString(className) && className !== '') {
11237            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
11238              nName = directiveNormalize(match[2]);
11239              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
11240                attrs[nName] = trim(match[3]);
11241              }
11242              className = className.substr(match.index + match[0].length);
11243            }
11244          }
11245          break;
11246        case 3: /* Text Node */
11247          addTextInterpolateDirective(directives, node.nodeValue);
11248          break;
11249        case 8: /* Comment */
11250          try {
11251            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
11252            if (match) {
11253              nName = directiveNormalize(match[1]);
11254              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
11255                attrs[nName] = trim(match[2]);
11256              }
11257            }
11258          } catch (e) {
11259            // turns out that under some circumstances IE9 throws errors when one attempts to read
11260            // comment's node value.
11261            // Just ignore it and continue. (Can't seem to reproduce in test case.)
11262          }
11263          break;
11264      }
11265
11266      directives.sort(byPriority);
11267      return directives;
11268    }
11269
11270    /**
11271     * Given a node with an directive-start it collects all of the siblings until it finds
11272     * directive-end.
11273     * @param node
11274     * @param attrStart
11275     * @param attrEnd
11276     * @returns {*}
11277     */
11278    function groupScan(node, attrStart, attrEnd) {
11279      var nodes = [];
11280      var depth = 0;
11281      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
11282        var startNode = node;
11283        do {
11284          if (!node) {
11285            throw $compileMinErr('uterdir',
11286                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
11287                      attrStart, attrEnd);
11288          }
11289          if (node.nodeType == 1 /** Element **/) {
11290            if (node.hasAttribute(attrStart)) depth++;
11291            if (node.hasAttribute(attrEnd)) depth--;
11292          }
11293          nodes.push(node);
11294          node = node.nextSibling;
11295        } while (depth > 0);
11296      } else {
11297        nodes.push(node);
11298      }
11299
11300      return jqLite(nodes);
11301    }
11302
11303    /**
11304     * Wrapper for linking function which converts normal linking function into a grouped
11305     * linking function.
11306     * @param linkFn
11307     * @param attrStart
11308     * @param attrEnd
11309     * @returns {Function}
11310     */
11311    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
11312      return function(scope, element, attrs, controllers, transcludeFn) {
11313        element = groupScan(element[0], attrStart, attrEnd);
11314        return linkFn(scope, element, attrs, controllers, transcludeFn);
11315      };
11316    }
11317
11318    /**
11319     * Once the directives have been collected, their compile functions are executed. This method
11320     * is responsible for inlining directive templates as well as terminating the application
11321     * of the directives if the terminal directive has been reached.
11322     *
11323     * @param {Array} directives Array of collected directives to execute their compile function.
11324     *        this needs to be pre-sorted by priority order.
11325     * @param {Node} compileNode The raw DOM node to apply the compile functions to
11326     * @param {Object} templateAttrs The shared attribute function
11327     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
11328     *                                                  scope argument is auto-generated to the new
11329     *                                                  child of the transcluded parent scope.
11330     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
11331     *                              argument has the root jqLite array so that we can replace nodes
11332     *                              on it.
11333     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
11334     *                                           compiling the transclusion.
11335     * @param {Array.<Function>} preLinkFns
11336     * @param {Array.<Function>} postLinkFns
11337     * @param {Object} previousCompileContext Context used for previous compilation of the current
11338     *                                        node
11339     * @returns {Function} linkFn
11340     */
11341    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
11342                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
11343                                   previousCompileContext) {
11344      previousCompileContext = previousCompileContext || {};
11345
11346      var terminalPriority = -Number.MAX_VALUE,
11347          newScopeDirective,
11348          controllerDirectives = previousCompileContext.controllerDirectives,
11349          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
11350          templateDirective = previousCompileContext.templateDirective,
11351          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
11352          hasTranscludeDirective = false,
11353          hasTemplate = false,
11354          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
11355          $compileNode = templateAttrs.$$element = jqLite(compileNode),
11356          directive,
11357          directiveName,
11358          $template,
11359          replaceDirective = originalReplaceDirective,
11360          childTranscludeFn = transcludeFn,
11361          linkFn,
11362          directiveValue;
11363
11364      // executes all directives on the current element
11365      for(var i = 0, ii = directives.length; i < ii; i++) {
11366        directive = directives[i];
11367        var attrStart = directive.$$start;
11368        var attrEnd = directive.$$end;
11369
11370        // collect multiblock sections
11371        if (attrStart) {
11372          $compileNode = groupScan(compileNode, attrStart, attrEnd);
11373        }
11374        $template = undefined;
11375
11376        if (terminalPriority > directive.priority) {
11377          break; // prevent further processing of directives
11378        }
11379
11380        if (directiveValue = directive.scope) {
11381          newScopeDirective = newScopeDirective || directive;
11382
11383          // skip the check for directives with async templates, we'll check the derived sync
11384          // directive when the template arrives
11385          if (!directive.templateUrl) {
11386            assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
11387                              $compileNode);
11388            if (isObject(directiveValue)) {
11389              newIsolateScopeDirective = directive;
11390            }
11391          }
11392        }
11393
11394        directiveName = directive.name;
11395
11396        if (!directive.templateUrl && directive.controller) {
11397          directiveValue = directive.controller;
11398          controllerDirectives = controllerDirectives || {};
11399          assertNoDuplicate("'" + directiveName + "' controller",
11400              controllerDirectives[directiveName], directive, $compileNode);
11401          controllerDirectives[directiveName] = directive;
11402        }
11403
11404        if (directiveValue = directive.transclude) {
11405          hasTranscludeDirective = true;
11406
11407          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
11408          // This option should only be used by directives that know how to safely handle element transclusion,
11409          // where the transcluded nodes are added or replaced after linking.
11410          if (!directive.$$tlb) {
11411            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
11412            nonTlbTranscludeDirective = directive;
11413          }
11414
11415          if (directiveValue == 'element') {
11416            hasElementTranscludeDirective = true;
11417            terminalPriority = directive.priority;
11418            $template = $compileNode;
11419            $compileNode = templateAttrs.$$element =
11420                jqLite(document.createComment(' ' + directiveName + ': ' +
11421                                              templateAttrs[directiveName] + ' '));
11422            compileNode = $compileNode[0];
11423            replaceWith(jqCollection, sliceArgs($template), compileNode);
11424
11425            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
11426                                        replaceDirective && replaceDirective.name, {
11427                                          // Don't pass in:
11428                                          // - controllerDirectives - otherwise we'll create duplicates controllers
11429                                          // - newIsolateScopeDirective or templateDirective - comb
11429ining templates with
11430                                          //   element transclusion doesn't make sense.
11431                                          //
11432                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
11433                                          // on the same element more than once.
11434                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
11435                                        });
11436          } else {
11437            $template = jqLite(jqLiteClone(compileNode)).contents();
11438            $compileNode.empty(); // clear contents
11439            childTranscludeFn = compile($template, transcludeFn);
11440          }
11441        }
11442
11443        if (directive.template) {
11444          hasTemplate = true;
11445          assertNoDuplicate('template', templateDirective, directive, $compileNode);
11446          templateDirective = directive;
11447
11448          directiveValue = (isFunction(directive.template))
11449              ? directive.template($compileNode, templateAttrs)
11450              : directive.template;
11451
11452          directiveValue = denormalizeTemplate(directiveValue);
11453
11454          if (directive.replace) {
11455            replaceDirective = directive;
11456            if (jqLiteIsTextNode(directiveValue)) {
11457              $template = [];
11458            } else {
11459              $template = jqLite(trim(directiveValue));
11460            }
11461            compileNode = $template[0];
11462
11463            if ($template.length != 1 || compileNode.nodeType !== 1) {
11464              throw $compileMinErr('tplrt',
11465                  "Template for directive '{0}' must have exactly one root element. {1}",
11466                  directiveName, '');
11467            }
11468
11469            replaceWith(jqCollection, $compileNode, compileNode);
11470
11471            var newTemplateAttrs = {$attr: {}};
11472
11473            // combine directives from the original node and from the template:
11474            // - take the array of directives for this element
11475            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
11476            // - collect directives from the template and sort them by priority
11477            // - combine directives as: processed + template + unprocessed
11478            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
11479            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
11480
11481            if (newIsolateScopeDirective) {
11482              markDirectivesAsIsolate(templateDirectives);
11483            }
11484            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
11485            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
11486
11487            ii = directives.length;
11488          } else {
11489            $compileNode.html(directiveValue);
11490          }
11491        }
11492
11493        if (directive.templateUrl) {
11494          hasTemplate = true;
11495          assertNoDuplicate('template', templateDirective, directive, $compileNode);
11496          templateDirective = directive;
11497
11498          if (directive.replace) {
11499            replaceDirective = directive;
11500          }
11501
11502          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
11503              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
11504                controllerDirectives: controllerDirectives,
11505                newIsolateScopeDirective: newIsolateScopeDirective,
11506                templateDirective: templateDirective,
11507                nonTlbTranscludeDirective: nonTlbTranscludeDirective
11508              });
11509          ii = directives.length;
11510        } else if (directive.compile) {
11511          try {
11512            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
11513            if (isFunction(linkFn)) {
11514              addLinkFns(null, linkFn, attrStart, attrEnd);
11515            } else if (linkFn) {
11516              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
11517            }
11518          } catch (e) {
11519            $exceptionHandler(e, startingTag($compileNode));
11520          }
11521        }
11522
11523        if (directive.terminal) {
11524          nodeLinkFn.terminal = true;
11525          terminalPriority = Math.max(terminalPriority, directive.priority);
11526        }
11527
11528      }
11529
11530      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
11531      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
11532      nodeLinkFn.templateOnThisElement = hasTemplate;
11533      nodeLinkFn.transclude = childTranscludeFn;
11534
11535      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
11536
11537      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
11538      return nodeLinkFn;
11539
11540      ////////////////////
11541
11542      function addLinkFns(pre, post, attrStart, attrEnd) {
11543        if (pre) {
11544          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
11545          pre.require = directive.require;
11546          pre.directiveName = directiveName;
11547          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
11548            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
11549          }
11550          preLinkFns.push(pre);
11551        }
11552        if (post) {
11553          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
11554          post.require = directive.require;
11555          post.directiveName = directiveName;
11556          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
11557            post = cloneAndAnnotateFn(post, {isolateScope: true});
11558          }
11559          postLinkFns.push(post);
11560        }
11561      }
11562
11563
11564      function getControllers(directiveName, require, $element, elementControllers) {
11565        var value, retrievalMethod = 'data', optional = false;
11566        if (isString(require)) {
11567          while((value = require.charAt(0)) == '^' || value == '?') {
11568            require = require.substr(1);
11569            if (value == '^') {
11570              retrievalMethod = 'inheritedData';
11571            }
11572            optional = optional || value == '?';
11573          }
11574          value = null;
11575
11576          if (elementControllers && retrievalMethod === 'data') {
11577            value = elementControllers[require];
11578          }
11579          value = value || $element[retrievalMethod]('$' + require + 'Controller');
11580
11581          if (!value && !optional) {
11582            throw $compileMinErr('ctreq',
11583                "Controller '{0}', required by directive '{1}', can't be found!",
11584                require, directiveName);
11585          }
11586          return value;
11587        } else if (isArray(require)) {
11588          value = [];
11589          forEach(require, function(require) {
11590            value.push(getControllers(directiveName, require, $element, elementControllers));
11591          });
11592        }
11593        return value;
11594      }
11595
11596
11597      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
11598        var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
11599
11600        attrs = (compileNode === linkNode)
11601          ? templateAttrs
11602          : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
11603        $element = attrs.$$element;
11604
11605        if (newIsolateScopeDirective) {
11606          var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
11607
11608          isolateScope = scope.$new(true);
11609
11610          if (templateDirective && (templateDirective === newIsolateScopeDirective ||
11611              templateDirective === newIsolateScopeDirective.$$originalDirective)) {
11612            $element.data('$isolateScope', isolateScope);
11613          } else {
11614            $element.data('$isolateScopeNoTemplate', isolateScope);
11615          }
11616
11617
11618
11619          safeAddClass($element, 'ng-isolate-scope');
11620
11621          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
11622            var match = definition.match(LOCAL_REGEXP) || [],
11623                attrName = match[3] || scopeName,
11624                optional = (match[2] == '?'),
11625                mode = match[1], // @, =, or &
11626                lastValue,
11627                parentGet, parentSet, compare;
11628
11629            isolateScope.$$isolateBindings[scopeName] = mode + attrName;
11630
11631            switch (mode) {
11632
11633              case '@':
11634                attrs.$observe(attrName, function(value) {
11635                  isolateScope[scopeName] = value;
11636                });
11637                attrs.$$observers[attrName].$$scope = scope;
11638                if( attrs[attrName] ) {
11639                  // If the attribute has been provided then we trigger an interpolation to ensure
11640                  // the value is there for use in the link fn
11641                  isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
11642                }
11643                break;
11644
11645              case '=':
11646                if (optional && !attrs[attrName]) {
11647                  return;
11648                }
11649                parentGet = $parse(attrs[attrName]);
11650                if (parentGet.literal) {
11651                  compare = equals;
11652                } else {
11653                  compare = function(a,b) { return a === b || (a !== a && b !== b); };
11654                }
11655                parentSet = parentGet.assign || function() {
11656                  // reset the change, or we will throw this exception on every $digest
11657                  lastValue = isolateScope[scopeName] = parentGet(scope);
11658                  throw $compileMinErr('nonassign',
11659                      "Expression '{0}' used with directive '{1}' is non-assignable!",
11660                      attrs[attrName], newIsolateScopeDirective.name);
11661                };
11662                lastValue = isolateScope[scopeName] = parentGet(scope);
11663                isolateScope.$watch(function parentValueWatch() {
11664                  var parentValue = parentGet(scope);
11665                  if (!compare(parentValue, isolateScope[scopeName])) {
11666                    // we are out of sync and need to copy
11667                    if (!compare(parentValue, lastValue)) {
11668                      // parent changed and it has precedence
11669                      isolateScope[scopeName] = parentValue;
11670                    } else {
11671                      // if the parent can be assigned then do so
11672                      parentSet(scope, parentValue = isolateScope[scopeName]);
11673                    }
11674                  }
11675                  return lastValue = parentValue;
11676                }, null, parentGet.literal);
11677                break;
11678
11679              case '&':
11680                parentGet = $parse(attrs[attrName]);
11681                isolateScope[scopeName] = function(locals) {
11682                  return parentGet(scope, locals);
11683                };
11684                break;
11685
11686              default:
11687                throw $compileMinErr('iscp',
11688                    "Invalid isolate scope definition for directive '{0}'." +
11689                    " Definition: {... {1}: '{2}' ...}",
11690                    newIsolateScopeDirective.name, scopeName, definition);
11691            }
11692          });
11693        }
11694        transcludeFn = boundTranscludeFn && controllersBoundTransclude;
11695        if (controllerDirectives) {
11696          forEach(controllerDirectives, function(directive) {
11697            var locals = {
11698              $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
11699              $element: $element,
11700              $attrs: attrs,
11701              $transclude: transcludeFn
11702            }, controllerInstance;
11703
11704            controller = directive.controller;
11705            if (controller == '@') {
11706              controller = attrs[directive.name];
11707            }
11708
11709            controllerInstance = $controller(controller, locals);
11710            // For directives with element transclusion the element is a comment,
11711            // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
11712            // clean up (http://bugs.jquery.com/ticket/8335).
11713            // Instead, we save the controllers for the element in a local hash and attach to .data
11714            // later, once we have the actual element.
11715            elementControllers[directive.name] = controllerInstance;
11716            if (!hasElementTranscludeDirective) {
11717              $element.data('$' + directive.name + 'Controller', controllerInstance);
11718            }
11719
11720            if (directive.controllerAs) {
11721              locals.$scope[directive.controllerAs] = controllerInstance;
11722            }
11723          });
11724        }
11725
11726        // PRELINKING
11727        for(i = 0, ii = preLinkFns.length; i < ii; i++) {
11728          try {
11729            linkFn = preLinkFns[i];
11730            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
11731                linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
11732          } catch (e) {
11733            $exceptionHandler(e, startingTag($element));
11734          }
11735        }
11736
11737        // RECURSION
11738        // We only pass the isolate scope, if the isolate directive has a template,
11739        // otherwise the child elements do not belong to the isolate directive.
11740        var scopeToChild = scope;
11741        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
11742          scopeToChild = isolateScope;
11743        }
11744        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
11745
11746        // POSTLINKING
11747        for(i = postLinkFns.length - 1; i >= 0; i--) {
11748          try {
11749            linkFn = postLinkFns[i];
11750            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
11751                linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
11752          } catch (e) {
11753            $exceptionHandler(e, startingTag($element));
11754          }
11755        }
11756
11757        // This is the function that is injected as `$transclude`.
11758        function controllersBoundTransclude(scope, cloneAttachFn) {
11759          var transcludeControllers;
11760
11761          // no scope passed
11762          if (arguments.length < 2) {
11763            cloneAttachFn = scope;
11764            scope = undefined;
11765          }
11766
11767          if (hasElementTranscludeDirective) {
11768            transcludeControllers = elementControllers;
11769          }
11770
11771          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
11772        }
11773      }
11774    }
11775
11776    function markDirectivesAsIsolate(directives) {
11777      // mark all directives as needing isolate scope.
11778      for (var j = 0, jj = directives.length; j < jj; j++) {
11779        directives[j] = inherit(directives[j], {$$isolateScope: true});
11780      }
11781    }
11782
11783    /**
11784     * looks up the directive and decorates it with exception handling and proper parameters. We
11785     * call this the boundDirective.
11786     *
11787     * @param {string} name name of the directive to look up.
11788     * @param {string} location The directive must be found in specific format.
11789     *   String containing any of theses characters:
11790     *
11791     *   * `E`: element name
11792     *   * `A': attribute
11793     *   * `C`: class
11794     *   * `M`: comment
11795     * @returns {boolean} true if directive was added.
11796     */
11797    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
11798                          endAttrName) {
11799      if (name === ignoreDirective) return null;
11800      var match = null;
11801      if (hasDirectives.hasOwnProperty(name)) {
11802        for(var directive, directives = $injector.get(name + Suffix),
11803            i = 0, ii = directives.length; i<ii; i++) {
11804          try {
11805            directive = directives[i];
11806            if ( (maxPriority === undefined || maxPriority > directive.priority) &&
11807                 directive.restrict.indexOf(location) != -1) {
11808              if (startAttrName) {
11809                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
11810              }
11811              tDirectives.push(directive);
11812              match = directive;
11813            }
11814          } catch(e) { $exceptionHandler(e); }
11815        }
11816      }
11817      return match;
11818    }
11819
11820
11821    /**
11822     * When the element is replaced with HTML template then the new attributes
11823     * on the template need to be merged with the existing attributes in the DOM.
11824     * The desired effect is to have both of the attributes present.
11825     *
11826     * @param {object} dst destination attributes (original DOM)
11827     * @param {object} src source attributes (from the directive template)
11828     */
11829    function mergeTemplateAttributes(dst, src) {
11830      var srcAttr = src.$attr,
11831          dstAttr = dst.$attr,
11832          $element = dst.$$element;
11833
11834      // reapply the old attributes to the new element
11835      forEach(dst, function(value, key) {
11836        if (key.charAt(0) != '$') {
11837          if (src[key] && src[key] !== value) {
11838            value += (key === 'style' ? ';' : ' ') + src[key];
11839          }
11840          dst.$set(key, value, true, srcAttr[key]);
11841        }
11842      });
11843
11844      // copy the new attributes on the old attrs object
11845      forEach(src, function(value, key) {
11846        if (key == 'class') {
11847          safeAddClass($element, value);
11848          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
11849        } else if (key == 'style') {
11850          $element.attr('style', $element.attr('style') + ';' + value);
11851          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
11852          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
11853          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
11854          // have an attribute like "has-own-property" or "data-has-own-property", etc.
11855        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
11856          dst[key] = value;
11857          dstAttr[key] = srcAttr[key];
11858        }
11859      });
11860    }
11861
11862
11863    function compileTemplateUrl(directives, $compileNode, tAttrs,
11864        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
11865      var linkQueue = [],
11866          afterTemplateNodeLinkFn,
11867          afterTemplateChildLinkFn,
11868          beforeTemplateCompileNode = $compileNode[0],
11869          origAsyncDirective = directives.shift(),
11870          // The fact that we have to copy and patch the directive seems wrong!
11871          derivedSyncDirective = extend({}, origAsyncDirective, {
11872            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
11873          }),
11874          templateUrl = (isFunction(origAsyncDirective.templateUrl))
11875              ? origAsyncDirective.templateUrl($compileNode, tAttrs
11875)
11876              : origAsyncDirective.templateUrl;
11877
11878      $compileNode.empty();
11879
11880      $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
11881        success(function(content) {
11882          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
11883
11884          content = denormalizeTemplate(content);
11885
11886          if (origAsyncDirective.replace) {
11887            if (jqLiteIsTextNode(content)) {
11888              $template = [];
11889            } else {
11890              $template = jqLite(trim(content));
11891            }
11892            compileNode = $template[0];
11893
11894            if ($template.length != 1 || compileNode.nodeType !== 1) {
11895              throw $compileMinErr('tplrt',
11896                  "Template for directive '{0}' must have exactly one root element. {1}",
11897                  origAsyncDirective.name, templateUrl);
11898            }
11899
11900            tempTemplateAttrs = {$attr: {}};
11901            replaceWith($rootElement, $compileNode, compileNode);
11902            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
11903
11904            if (isObject(origAsyncDirective.scope)) {
11905              markDirectivesAsIsolate(templateDirectives);
11906            }
11907            directives = templateDirectives.concat(directives);
11908            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
11909          } else {
11910            compileNode = beforeTemplateCompileNode;
11911            $compileNode.html(content);
11912          }
11913
11914          directives.unshift(derivedSyncDirective);
11915
11916          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
11917              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
11918              previousCompileContext);
11919          forEach($rootElement, function(node, i) {
11920            if (node == compileNode) {
11921              $rootElement[i] = $compileNode[0];
11922            }
11923          });
11924          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
11925
11926          while(linkQueue.length) {
11927            var scope = linkQueue.shift(),
11928                beforeTemplateLinkNode = linkQueue.shift(),
11929                linkRootElement = linkQueue.shift(),
11930                boundTranscludeFn = linkQueue.shift(),
11931                linkNode = $compileNode[0];
11932
11933            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
11934              var oldClasses = beforeTemplateLinkNode.className;
11935
11936              if (!(previousCompileContext.hasElementTranscludeDirective &&
11937                  origAsyncDirective.replace)) {
11938                // it was cloned therefore we have to clone as well.
11939                linkNode = jqLiteClone(compileNode);
11940              }
11941
11942              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
11943
11944              // Copy in CSS classes from original node
11945              safeAddClass(jqLite(linkNode), oldClasses);
11946            }
11947            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
11948              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
11949            } else {
11950              childBoundTranscludeFn = boundTranscludeFn;
11951            }
11952            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
11953              childBoundTranscludeFn);
11954          }
11955          linkQueue = null;
11956        }).
11957        error(function(response, code, headers, config) {
11958          throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
11959        });
11960
11961      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
11962        var childBoundTranscludeFn = boundTranscludeFn;
11963        if (linkQueue) {
11964          linkQueue.push(scope);
11965          linkQueue.push(node);
11966          linkQueue.push(rootElement);
11967          linkQueue.push(childBoundTranscludeFn);
11968        } else {
11969          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
11970            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
11971          }
11972          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
11973        }
11974      };
11975    }
11976
11977
11978    /**
11979     * Sorting function for bound directives.
11980     */
11981    function byPriority(a, b) {
11982      var diff = b.priority - a.priority;
11983      if (diff !== 0) return diff;
11984      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
11985      return a.index - b.index;
11986    }
11987
11988
11989    function assertNoDuplicate(what, previousDirective, directive, element) {
11990      if (previousDirective) {
11991        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
11992            previousDirective.name, directive.name, what, startingTag(element));
11993      }
11994    }
11995
11996
11997      function addTextInterpolateDirective(directives, text) {
11998        var interpolateFn = $interpolate(text, true);
11999        if (interpolateFn) {
12000          directives.push({
12001            priority: 0,
12002            compile: function textInterpolateCompileFn(templateNode) {
12003              // when transcluding a template that has bindings in the root
12004              // then we don't have a parent and should do this in the linkFn
12005              var parent = templateNode.parent(), hasCompileParent = parent.length;
12006              if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
12007
12008              return function textInterpolateLinkFn(scope, node) {
12009                var parent = node.parent(),
12010                  bindings = parent.data('$binding') || [];
12011                bindings.push(interpolateFn);
12012                parent.data('$binding', bindings);
12013                if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
12014                scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
12015                  node[0].nodeValue = value;
12016                });
12017              };
12018            }
12019          });
12020        }
12021      }
12022
12023
12024    function getTrustedContext(node, attrNormalizedName) {
12025      if (attrNormalizedName == "srcdoc") {
12026        return $sce.HTML;
12027      }
12028      var tag = nodeName_(node);
12029      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
12030      if (attrNormalizedName == "xlinkHref" ||
12031          (tag == "FORM" && attrNormalizedName == "action") ||
12032          (tag != "IMG" && (attrNormalizedName == "src" ||
12033                            attrNormalizedName == "ngSrc"))) {
12034        return $sce.RESOURCE_URL;
12035      }
12036    }
12037
12038
12039    function addAttrInterpolateDirective(node, directives, value, name) {
12040      var interpolateFn = $interpolate(value, true);
12041
12042      // no interpolation found -> ignore
12043      if (!interpolateFn) return;
12044
12045
12046      if (name === "multiple" && nodeName_(node) === "SELECT") {
12047        throw $compileMinErr("selmulti",
12048            "Binding to the 'multiple' attribute is not supported. Element: {0}",
12049            startingTag(node));
12050      }
12051
12052      directives.push({
12053        priority: 100,
12054        compile: function() {
12055            return {
12056              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
12057                var $$observers = (attr.$$observers || (attr.$$observers = {}));
12058
12059                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
12060                  throw $compileMinErr('nodomevents',
12061                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
12062                          "ng- versions (such as ng-click instead of onclick) instead.");
12063                }
12064
12065                // we need to interpolate again, in case the attribute value has been updated
12066                // (e.g. by another directive's compile function)
12067                interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
12068
12069                // if attribute was updated so that there is no interpolation going on we don't want to
12070                // register any observers
12071                if (!interpolateFn) return;
12072
12073                // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
12074                // actual attr value
12075                attr[name] = interpolateFn(scope);
12076                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
12077                (attr.$$observers && attr.$$observers[name].$$scope || scope).
12078                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
12079                    //special case for class attribute addition + removal
12080                    //so that class changes can tap into the animation
12081                    //hooks provided by the $animate service. Be sure to
12082                    //skip animations when the first digest occurs (when
12083                    //both the new and the old values are the same) since
12084                    //the CSS classes are the non-interpolated values
12085                    if(name === 'class' && newValue != oldValue) {
12086                      attr.$updateClass(newValue, oldValue);
12087                    } else {
12088                      attr.$set(name, newValue);
12089                    }
12090                  });
12091              }
12092            };
12093          }
12094      });
12095    }
12096
12097
12098    /**
12099     * This is a special jqLite.replaceWith, which can replace items which
12100     * have no parents, provided that the containing jqLite collection is provided.
12101     *
12102     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
12103     *                               in the root of the tree.
12104     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
12105     *                                  the shell, but replace its DOM node reference.
12106     * @param {Node} newNode The new DOM node.
12107     */
12108    function replaceWith($rootElement, elementsToRemove, newNode) {
12109      var firstElementToRemove = elementsToRemove[0],
12110          removeCount = elementsToRemove.length,
12111          parent = firstElementToRemove.parentNode,
12112          i, ii;
12113
12114      if ($rootElement) {
12115        for(i = 0, ii = $rootElement.length; i < ii; i++) {
12116          if ($rootElement[i] == firstElementToRemove) {
12117            $rootElement[i++] = newNode;
12118            for (var j = i, j2 = j + removeCount - 1,
12119                     jj = $rootElement.length;
12120                 j < jj; j++, j2++) {
12121              if (j2 < jj) {
12122                $rootElement[j] = $rootElement[j2];
12123              } else {
12124                delete $rootElement[j];
12125              }
12126            }
12127            $rootElement.length -= removeCount - 1;
12128            break;
12129          }
12130        }
12131      }
12132
12133      if (parent) {
12134        parent.replaceChild(newNode, firstElementToRemove);
12135      }
12136      var fragment = document.createDocumentFragment();
12137      fragment.appendChild(firstElementToRemove);
12138      newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
12139      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
12140        var element = elementsToRemove[k];
12141        jqLite(element).remove(); // must do this way to clean up expando
12142        fragment.appendChild(element);
12143        delete elementsToRemove[k];
12144      }
12145
12146      elementsToRemove[0] = newNode;
12147      elementsToRemove.length = 1;
12148    }
12149
12150
12151    function cloneAndAnnotateFn(fn, annotation) {
12152      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
12153    }
12154  }];
12155}
12156
12157var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
12158/**
12159 * Converts all accepted directives format into proper directive name.
12160 * All of these will become 'myDirective':
12161 *   my:Directive
12162 *   my-directive
12163 *   x-my-directive
12164 *   data-my:directive
12165 *
12166 * Also there is special case for Moz prefix starting with upper case letter.
12167 * @param name Name to normalize
12168 */
12169function directiveNormalize(name) {
12170  return camelCase(name.replace(PREFIX_REGEXP, ''));
12171}
12172
12173/**
12174 * @ngdoc type
12175 * @name $compile.directive.Attributes
12176 *
12177 * @description
12178 * A shared object between directive compile / linking functions which contains 
12178normalized DOM
12179 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
12180 * needed since all of these are treated as equivalent in Angular:
12181 *
12182 * ```
12183 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
12184 * ```
12185 */
12186
12187/**
12188 * @ngdoc property
12189 * @name $compile.directive.Attributes#$attr
12190 *
12191 * @description
12192 * A map of DOM element attribute names to the normalized name. This is
12193 * needed to do reverse lookup from normalized name back to actual name.
12194 */
12195
12196
12197/**
12198 * @ngdoc method
12199 * @name $compile.directive.Attributes#$set
12200 * @kind function
12201 *
12202 * @description
12203 * Set DOM element attribute value.
12204 *
12205 *
12206 * @param {string} name Normalized element attribute name of the property to modify. The name is
12207 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
12208 *          property to the original name.
12209 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
12210 */
12211
12212
12213
12214/**
12215 * Closure compiler type information
12216 */
12217
12218function nodesetLinkingFn(
12219  /* angular.Scope */ scope,
12220  /* NodeList */ nodeList,
12221  /* Element */ rootElement,
12222  /* function(Function) */ boundTranscludeFn
12223){}
12224
12225function directiveLinkingFn(
12226  /* nodesetLinkingFn */ nodesetLinkingFn,
12227  /* angular.Scope */ scope,
12228  /* Node */ node,
12229  /* Element */ rootElement,
12230  /* function(Function) */ boundTranscludeFn
12231){}
12232
12233function tokenDifference(str1, str2) {
12234  var values = '',
12235      tokens1 = str1.split(/\s+/),
12236      tokens2 = str2.split(/\s+/);
12237
12238  outer:
12239  for(var i = 0; i < tokens1.length; i++) {
12240    var token = tokens1[i];
12241    for(var j = 0; j < tokens2.length; j++) {
12242      if(token == tokens2[j]) continue outer;
12243    }
12244    values += (values.length > 0 ? ' ' : '') + token;
12245  }
12246  return values;
12247}
12248
12249/**
12250 * @ngdoc provider
12251 * @name $controllerProvider
12252 * @description
12253 * The {@link ng.$controller $controller service} is used by Angular to create new
12254 * controllers.
12255 *
12256 * This provider allows controller registration via the
12257 * {@link ng.$controllerProvider#register register} method.
12258 */
12259function $ControllerProvider() {
12260  var controllers = {},
12261      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
12262
12263
12264  /**
12265   * @ngdoc method
12266   * @name $controllerProvider#register
12267   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
12268   *    the names and the values are the constructors.
12269   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
12270   *    annotations in the array notation).
12271   */
12272  this.register = function(name, constructor) {
12273    assertNotHasOwnProperty(name, 'controller');
12274    if (isObject(name)) {
12275      extend(controllers, name);
12276    } else {
12277      controllers[name] = constructor;
12278    }
12279  };
12280
12281
12282  this.$get = ['$injector', '$window', function($injector, $window) {
12283
12284    /**
12285     * @ngdoc service
12286     * @name $controller
12287     * @requires $injector
12288     *
12289     * @param {Function|string} constructor If called with a function then it's considered to be the
12290     *    controller constructor function. Otherwise it's considered to be a string which is used
12291     *    to retrieve the controller constructor using the following steps:
12292     *
12293     *    * check if a controller with given name is registered via `$controllerProvider`
12294     *    * check if evaluating the string on the current scope returns a constructor
12295     *    * check `window[constructor]` on the global `window` object
12296     *
12297     * @param {Object} locals Injection locals for Controller.
12298     * @return {Object} Instance of given controller.
12299     *
12300     * @description
12301     * `$controller` service is responsible for instantiating controllers.
12302     *
12303     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
12304     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
12305     */
12306    return function(expression, locals) {
12307      var instance, match, constructor, identifier;
12308
12309      if(isString(expression)) {
12310        match = expression.match(CNTRL_REG),
12311        constructor = match[1],
12312        identifier = match[3];
12313        expression = controllers.hasOwnProperty(constructor)
12314            ? controllers[constructor]
12315            : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
12316
12317        assertArgFn(expression, constructor, true);
12318      }
12319
12320      instance = $injector.instantiate(expression, locals);
12321
12322      if (identifier) {
12323        if (!(locals && typeof locals.$scope === 'object')) {
12324          throw minErr('$controller')('noscp',
12325              "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
12326              constructor || expression.name, identifier);
12327        }
12328
12329        locals.$scope[identifier] = instance;
12330      }
12331
12332      return instance;
12333    };
12334  }];
12335}
12336
12337/**
12338 * @ngdoc service
12339 * @name $document
12340 * @requires $window
12341 *
12342 * @description
12343 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
12344 *
12345 * @example
12346   <example module="documentExample">
12347     <file name="index.html">
12348       <div ng-controller="ExampleController">
12349         <p>$document title: <b ng-bind="title"></b></p>
12350         <p>window.document title: <b ng-bind="windowTitle"></b></p>
12351       </div>
12352     </file>
12353     <file name="script.js">
12354       angular.module('documentExample', [])
12355         .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
12356           $scope.title = $document[0].title;
12357           $scope.windowTitle = angular.element(window.document)[0].title;
12358         }]);
12359     </file>
12360   </example>
12361 */
12362function $DocumentProvider(){
12363  this.$get = ['$window', function(window){
12364    return jqLite(window.document);
12365  }];
12366}
12367
12368/**
12369 * @ngdoc service
12370 * @name $exceptionHandler
12371 * @requires ng.$log
12372 *
12373 * @description
12374 * Any uncaught exception in angular expressions is delegated to this service.
12375 * The default implementation simply delegates to `$log.error` which logs it into
12376 * the browser console.
12377 *
12378 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
12379 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
12380 *
12381 * ## Example:
12382 *
12383 * ```js
12384 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
12385 *     return function (exception, cause) {
12386 *       exception.message += ' (caused by "' + cause + '")';
12387 *       throw exception;
12388 *     };
12389 *   });
12390 * ```
12391 *
12392 * This example will override the normal action of `$exceptionHandler`, to make angular
12393 * exceptions fail hard when they happen, instead of just logging to the console.
12394 *
12395 * @param {Error} exception Exception associated with the error.
12396 * @param {string=} cause optional information about the context in which
12397 *       the error was thrown.
12398 *
12399 */
12400function $ExceptionHandlerProvider() {
12401  this.$get = ['$log', function($log) {
12402    return function(exception, cause) {
12403      $log.error.apply($log, arguments);
12404    };
12405  }];
12406}
12407
12408/**
12409 * Parse headers into key value object
12410 *
12411 * @param {string} headers Raw headers as a string
12412 * @returns {Object} Parsed headers as key value object
12413 */
12414function parseHeaders(headers) {
12415  var parsed = {}, key, val, i;
12416
12417  if (!headers) return parsed;
12418
12419  forEach(headers.split('\n'), function(line) {
12420    i = line.indexOf(':');
12421    key = lowercase(trim(line.substr(0, i)));
12422    val = trim(line.substr(i + 1));
12423
12424    if (key) {
12425      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
12426    }
12427  });
12428
12429  return parsed;
12430}
12431
12432
12433/**
12434 * Returns a function that provides access to parsed headers.
12435 *
12436 * Headers are lazy parsed when first requested.
12437 * @see parseHeaders
12438 *
12439 * @param {(string|Object)} headers Headers to provide access to.
12440 * @returns {function(string=)} Returns a getter function which if called with:
12441 *
12442 *   - if called with single an argument returns a single header value or null
12443 *   - if called with no arguments returns an object containing all headers.
12444 */
12445function headersGetter(headers) {
12446  var headersObj = isObject(headers) ? headers : undefined;
12447
12448  return function(name) {
12449    if (!headersObj) headersObj =  parseHeaders(headers);
12450
12451    if (name) {
12452      return headersObj[lowercase(name)] || null;
12453    }
12454
12455    return headersObj;
12456  };
12457}
12458
12459
12460/**
12461 * Chain all given functions
12462 *
12463 * This function is used for both request and response transforming
12464 *
12465 * @param {*} data Data to transform.
12466 * @param {function(string=)} headers Http headers getter fn.
12467 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
12468 * @returns {*} Transformed data.
12469 */
12470function transformData(data, headers, fns) {
12471  if (isFunction(fns))
12472    return fns(data, headers);
12473
12474  forEach(fns, function(fn) {
12475    data = fn(data, headers);
12476  });
12477
12478  return data;
12479}
12480
12481
12482function isSuccess(status) {
12483  return 200 <= status && status < 300;
12484}
12485
12486
12487/**
12488 * @ngdoc provider
12489 * @name $httpProvider
12490 * @description
12491 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
12492 * */
12493function $HttpProvider() {
12494  var JSON_START = /^\s*(\[|\{[^\{])/,
12495      JSON_END = /[\}\]]\s*$/,
12496      PROTECTION_PREFIX = /^\)\]\}',?\n/,
12497      CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
12498
12499  /**
12500   * @ngdoc property
12501   * @name $httpProvider#defaults
12502   * @description
12503   *
12504   * Object containing default values for all {@link ng.$http $http} requests.
12505   *
12506   * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
12507   * Defaults value is `'XSRF-TOKEN'`.
12508   *
12509   * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
12510   * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
12511   *
12512   * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
12513   * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
12514   * setting default headers.
12515   *     - **`defaults.headers.common`**
12516   *     - **`defaults.headers.post`**
12517   *     - **`defaults.headers.put`**
12518   *     - **`defaults.headers.patch`**
12519   **/
12520  var defaults = this.defaults = {
12521    // transform incoming response data
12522    transformResponse: [function(data) {
12523      if (isString(data)) {
12524        // strip json vulnerability protection prefix
12525        data = data.replace(PROTECTION_PREFIX, '');
12526        if (JSON_START.test(data) && JSON_END.test(data))
12527          data = fromJson(data);
12528      }
12529      return data;
12530    }],
12531
12532    // transform outgoing request data
12533    transformRequest: [function(d) {
12534      return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
12535    }],
12536
12537    // default headers
12538    headers: {
12539      common: {
12540        'Accept': 'application/json, text/plain, */*'
12541      },
12542      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
12543      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
12544      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
12545    },
12546
12547    xsrfCookieName: 'XSRF-TOKEN',
12548    xsrfHeaderName: 'X-XSRF-TOKEN'
12549  };
12550
12551  /**
12552   * Are ordered by request, i.e. they are applied in the same order as the
12553   * array, on request, but reverse order, on response.
12554   */
12555  var interceptorFactories = this.interceptors = [];
12556
12557  /**
12558   * For historical reasons, response interceptors are ordered by the order in which
12559   * they are applied to the response. (This is the opposite of interceptorFactories)
12560   */
12561  var responseInterceptorFactories = this.responseInterceptors = [];
12562
12563  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
12564      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
12565
12566    var defaultCache = $cacheFactory('$http');
12567
12568    /**
12569     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
12570     * The reversal is needed so that we can build up the interception chain around the
12571     * server request.
12572     */
12573    var reversedInterceptors = [];
12574
12575    forEach(interceptorFactories, function(interceptorFactory) {
12576      reversedInterceptors.unshift(isString(interceptorFactory)
12577          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
12578    });
12579
12580    forEach(responseInterceptorFactories, function(interceptorFactory, index) {
12581      var responseFn = isString(interceptorFactory)
12582          ? $injector.get(interceptorFactory)
12583          : $injector.invoke(interceptorFactory);
12584
12585      /**
12586       * Response interceptors go before "around" interceptors (no real reason, just
12587       * had to pick one.) But they are already reversed, so we can't use unshift, hence
12588       * the splice.
12589       */
12590      reversedInterceptors.splice(index, 0, {
12591        response: function(response) {
12592          return responseFn($q.when(response));
12593        },
12594        responseError: function(response) {
12595          return responseFn($q.reject(response));
12596        }
12597      });
12598    });
12599
12600
12601    /**
12602     * @ngdoc service
12603     * @kind function
12604     * @name $http
12605     * @requires ng.$httpBackend
12606     * @requires $cacheFactory
12607     * @requires $rootScope
12608     * @requires $q
12609     * @requires $injector
12610     *
12611     * @description
12612     * The `$http` service is a core Angular service that facilitates communication with the remote
12613     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
12614     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
12615     *
12616     * For unit testing applications that use `$http` service, see
12617     * {@link ngMock.$httpBackend $httpBackend mock}.
12618     *
12619     * For a higher level of abstraction, please check out the {@link ngResource.$resource
12620     * $resource} service.
12621     *
12622     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
12623     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
12624     * it is important to familiarize yourself with these APIs and the guarantees they provide.
12625     *
12626     *
12627     * # General usage
12628     * The `$http` service is a function which takes a single argument — a configuration object —
12629     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
12630     * with two $http specific methods: `success` and `error`.
12631     *
12632     * ```js
12633     *   $http({method: 'GET', url: '/someUrl'}).
12634     *     success(function(data, status, headers, config) {
12635     *       // this callback will be called asynchronously
12636     *       // when the response is available
12637     *     }).
12638     *     error(function(data, status, headers, config) {
12639     *       // called asynchronously if an error occurs
12640     *       // or server returns response with an error status.
12641     *     });
12642     * ```
12643     *
12644     * Since the returned value of calling the $http function is a `promise`, you can also use
12645     * the `then` method to register callbacks, and these callbacks will receive a single argument –
12646     * an object representing the response. See the API signature and type info below for more
12647     * details.
12648     *
12649     * A response status code between 200 and 299 is considered a success status and
12650     * will result in the success callback being called. Note that if the response is a redirect,
12651     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
12652     * called for such responses.
12653     *
12654     * # Writing Unit Tests that use $http
12655     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
12656     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
12657     * request using trained responses.
12658     *
12659     * ```
12660     * $httpBackend.expectGET(...);
12661     * $http.get(...);
12662     * $httpBackend.flush();
12663     * ```
12664     *
12665     * # Shortcut methods
12666     *
12667     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
12668     * request data must be passed in for POST/PUT requests.
12669     *
12670     * ```js
12671     *   $http.get('/someUrl').success(successCallback);
12672     *   $http.post('/someUrl', data).success(successCallback);
12673     * ```
12674     *
12675     * Complete list of shortcut methods:
12676     *
12677     * - {@link ng.$http#get $http.get}
12678     * - {@link ng.$http#head $http.head}
12679     * - {@link ng.$http#post $http.post}
12680     * - {@link ng.$http#put $http.put}
12681     * - {@link ng.$http#delete $http.delete}
12682     * - {@link ng.$http#jsonp $http.jsonp}
12683     * - {@link ng.$http#patch $http.patch}
12684     *
12685     *
12686     * # Setting HTTP Headers
12687     *
12688     * The $http service will automatically add certain HTTP headers to all requests. These defaults
12689     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
12690     * object, which currently contains this default configuration:
12691     *
12692     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
12693     *   - `Accept: application/json, text/plain, * / *`
12694     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
12695     *   - `Content-Type: application/json`
12696     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
12697     *   - `Content-Type: application/json`
12698     *
12699     * To add or overwrite these defaults, simply add or remove a property from these configuration
12700     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
12701     * with the lowercased HTTP method name as the key, e.g.
12702     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
12703     *
12704     * The defaults can also be set at runtime via the `$http.defaults` object in the same
12705     * fashion. For example:
12706     *
12707     * ```
12708     * module.run(function($http) {
12709     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
12710     * });
12711     * ```
12712     *
12713     * In addition, you can supply a `headers` property in the config object passed when
12714     * calling `$http(config)`, which overrides the defaults without changing them globally.
12715     *
12716     *
12717     * # Transforming Requests and Responses
12718     *
12719     * Both requests and responses can be transformed using transform functions. By default, Angular
12720     * applies these transformations:
12721     *
12722     * Request transformations:
12723     *
12724     * - If the `data` property of the request configuration object contains an object, serialize it
12725     *   into JSON format.
12726     *
12727     * Response transformations:
12728     *
12729     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
12730     *  - If JSON response is detected, deserialize it using a JSON parser.
12731     *
12732     * To globally augment or override the default transforms, modify the
12733     * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
12734     * properties. These properties are by default an array of transform functions, which allows you
12735     * to `push` or `unshift` a new transformation function into the transformation chain. You can
12736     * also decide to completely override any default transformations by assigning your
12737     * transformation functions to these properties directly without the array wrapper.  These defaults
12738     * are again available on the $http factory at run-time, which may be useful if you have run-time
12739     * services you wish to be involved in your transformations.
12740     *
12741     * Similarly, to locally override the request/response transforms, augment the
12742     * `transformRequest` and/or `transformResponse` properties of the configuration object passed
12743     * into `$http`.
12744     *
12745     *
12746     * # Caching
12747     *
12748     * To enable caching, set the request configuration `cache` property to `true` (to use default
12749     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
12750     * When the cache is enabled, `$http` stores the response from the server in the specified
12751     * cache. The next time the same request is made, the response is served from the cache without
12752     * sending a request to the server.
12753     *
12754     * Note that even if the response is served from cache, delivery of the data is asynchronous in
12755     * the same way that real requests are.
12756     *
12757     * If there are multiple GET requests for the same URL that should be cached using the same
12758     * cache, but the cache is not populated yet, only one request to the server will be made and
12759     * the remaining requests will be fulfilled using the response from the first request.
12760     *
12761     * You can change the default cache to a new object (built with
12762     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
12763     * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
12764     * their `cache` property to `true` will now use this cache object.
12765     *
12766     * If you set the default cache to `false` then only requests that specify their own custom
12767     * cache object will be cached.
12768     *
12769     * # Interceptors
12770     *
12771     * Before you start creating interceptors, be sure to understand the
12772     * {@link ng.$q $q and deferred/promise APIs}.
12773     *
12774     * For purposes of global error handling, authentication, or any kind of synchronous or
12775     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
12776     * able to intercept requests before they are handed to the server and
12777     * responses before they are handed over to the application code that
12778     * initiated these requests. The interceptors leverage the {@link ng.$q
12779     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
12780     *
12781     * The interceptors are service factories that are registered with the `$httpProvider` by
12782     * adding them to the `$httpProvider.interceptors` array. The factory is called and
12783     * injected with dependencies (if specified) and returns the interceptor.
12784     *
12785     * There are two kinds of interceptors (and two kinds of rejection interceptors):
12786     *
12787     *   * `request`: interceptors get called with a http `config` object. The function is free to
12788     *     modify the `config` object or create a new one. The function needs to return the `config`
12789     *     object directly, or a promise containing the `config` or a new `config` object.
12790     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
12791     *     resolved with a rejection.
12792     *   * `response`: interceptors get called with http `response` object. The function is free to
12793     *     modify the `response` object or create a new one. The function needs to return the `response`
12794     *     object directly, or as a promise containing the `response` or a new `response` object.
12795     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
12796     *     resolved with a rejection.
12797     *
12798     *
12799     * ```js
12800     *   // register the interceptor as a service
12801     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
12802     *     return {
12803     *       // optional method
12804     *       'request': function(config) {
12805     *         // do something on success
12806     *         return config;
12807     *       },
12808     *
12809     *       // optional method
12810     *      'requestError': function(rejection) {
12811     *         // do something on error
12812     *         if (canRecover(rejection)) {
12813     *           return responseOrNewPromise
12814     *         }
12815     *         return $q.reject(rejection);
12816     *       },
12817     *
12818     *
12819     *
12820     *       // optional method
12821     *       'response': function(response) {
12822     *         // do something on success
12823     *         return response;
12824     *       },
12825     *
12826     *       // optional method
12827     *      'responseError': function(rejection) {
12828     *         // do something on error
12829     *         if (canRecover(rejection)) {
12830     *           return responseOrNewPromise
12831     *         }
12832     *         return $q.reject(rejection);
12833     *       }
12834     *     };
12835     *   });
12836     *
12837     *   $httpProvider.interceptors.push('myHttpInterceptor');
12838     *
12839     *
12840     *   // alternatively, register the interceptor via an anonymous factory
12841     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
12842     *     return {
12843     *      'request': function(config) {
12844     *          // same as above
12845     *       },
12846     *
12847     *       'response': function(response) {
12848     *          // same as above
12849     *       }
12850     *     };
12851     *   });
12852     * ```
12853     *
12854     * # Response interceptors (DEPRECATED)
12855     *
12856     * Before you start creating interceptors, be sure to understand the
12857     * {@link ng.$q $q and deferred/promise APIs}.
12858     *
12859     * For purposes of global error handling, authentication or any kind of synchronous or
12860     * asynchronous preprocessing of received responses, it is desirable to be able to intercept
12861     * responses for http requests before they are handed over to the application code that
12862     * initiated these requests. The response interceptors leverage the {@link ng.$q
12863     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
12864     *
12865     * The interceptors are service factories that are registered with the $httpProvider by
12866     * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
12867     * injected with dependencies (if specified) and returns the interceptor  — a function that
12868     * takes a {@link ng.$q promise} and returns the original or a new promise.
12869     *
12870     * ```js
12871     *   // register the interceptor as a service
12872     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
12873     *     return function(promise) {
12874     *       return promise.then(function(response) {
12875     *         // do something on success
12876     *         return response;
12877     *       }, function(response) {
12878     *         // do something on error
12879     *         if (canRecover(response)) {
12880     *           return responseOrNewPromise
12881     *         }
12882     *         return $q.reject(response);
12883     *       });
12884     *     }
12885     *   });
12886     *
12887     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
12888     *
12889     *
12890     *   // register the interceptor via an anonymous factory
12891     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
12892     *     return function(promise) {
12893     *       // same as above
12894     *     }
12895     *   });
12896     * ```
12897     *
12898     *
12899     * # Security Considerations
12900     *
12901     * When designing web applications, consider security threats from:
12902     *
12903     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
12904     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
12905     *
12906     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
12907     * pre-configured with strategies that address these issues, but for this to work backend server
12908     * cooperation is required.
12909     *
12910     * ## JSON Vulnerability Protection
12911     *
12912     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
12913     * allows third party website to turn your JSON resource URL into
12914     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
12915     * counter this your server can prefix all JSON requests with following str
12915ing `")]}',\n"`.
12916     * Angular will automatically strip the prefix before processing it as JSON.
12917     *
12918     * For example if your server needs to return:
12919     * ```js
12920     * ['one','two']
12921     * ```
12922     *
12923     * which is vulnerable to attack, your server can return:
12924     * ```js
12925     * )]}',
12926     * ['one','two']
12927     * ```
12928     *
12929     * Angular will strip the prefix, before processing the JSON.
12930     *
12931     *
12932     * ## Cross Site Request Forgery (XSRF) Protection
12933     *
12934     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
12935     * an unauthorized site can gain your user's private data. Angular provides a mechanism
12936     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
12937     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
12938     * JavaScript that runs on your domain could read the cookie, your server can be assured that
12939     * the XHR came from JavaScript running on your domain. The header will not be set for
12940     * cross-domain requests.
12941     *
12942     * To take advantage of this, your server needs to set a token in a JavaScript readable session
12943     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
12944     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
12945     * that only JavaScript running on your domain could have sent the request. The token must be
12946     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
12947     * making up its own tokens). We recommend that the token is a digest of your site's
12948     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
12949     * for added security.
12950     *
12951     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
12952     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
12953     * or the per-request config object.
12954     *
12955     *
12956     * @param {object} config Object describing the request to be made and how it should be
12957     *    processed. The object has following properties:
12958     *
12959     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
12960     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
12961     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
12962     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
12963     *      JSONified.
12964     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
12965     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
12966     *      HTTP headers to send to the server. If the return value of a function is null, the
12967     *      header will not be sent.
12968     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
12969     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
12970     *    - **transformRequest** –
12971     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
12972     *      transform function or an array of such functions. The transform function takes the http
12973     *      request body and headers and returns its transformed (typically serialized) version.
12974     *    - **transformResponse** –
12975     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
12976     *      transform function or an array of such functions. The transform function takes the http
12977     *      response body and headers and returns its transformed (typically deserialized) version.
12978     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
12979     *      GET request, otherwise if a cache instance built with
12980     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
12981     *      caching.
12982     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
12983     *      that should abort the request when resolved.
12984     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
12985     *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
12986     *      for more information.
12987     *    - **responseType** - `{string}` - see
12988     *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
12989     *
12990     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
12991     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
12992     *   method takes two arguments a success and an error callback which will be called with a
12993     *   response object. The `success` and `error` methods take a single argument - a function that
12994     *   will be called when the request succeeds or fails respectively. The arguments passed into
12995     *   these functions are destructured representation of the response object passed into the
12996     *   `then` method. The response object has these properties:
12997     *
12998     *   - **data** – `{string|Object}` – The response body transformed with the transform
12999     *     functions.
13000     *   - **status** – `{number}` – HTTP status code of the response.
13001     *   - **headers** – `{function([headerName])}` – Header getter function.
13002     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
13003     *   - **statusText** – `{string}` – HTTP status text of the response.
13004     *
13005     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
13006     *   requests. This is primarily meant to be used for debugging purposes.
13007     *
13008     *
13009     * @example
13010<example module="httpExample">
13011<file name="index.html">
13012  <div ng-controller="FetchController">
13013    <select ng-model="method">
13014      <option>GET</option>
13015      <option>JSONP</option>
13016    </select>
13017    <input type="text" ng-model="url" size="80"/>
13018    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
13019    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
13020    <button id="samplejsonpbtn"
13021      ng-click="updateModel('JSONP',
13022                    'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
13023      Sample JSONP
13024    </button>
13025    <button id="invalidjsonpbtn"
13026      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
13027        Invalid JSONP
13028      </button>
13029    <pre>http status code: {{status}}</pre>
13030    <pre>http response data: {{data}}</pre>
13031  </div>
13032</file>
13033<file name="script.js">
13034  angular.module('httpExample', [])
13035    .controller('FetchController', ['$scope', '$http', '$templateCache',
13036      function($scope, $http, $templateCache) {
13037        $scope.method = 'GET';
13038        $scope.url = 'http-hello.html';
13039
13040        $scope.fetch = function() {
13041          $scope.code = null;
13042          $scope.response = null;
13043
13044          $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
13045            success(function(data, status) {
13046              $scope.status = status;
13047              $scope.data = data;
13048            }).
13049            error(function(data, status) {
13050              $scope.data = data || "Request failed";
13051              $scope.status = status;
13052          });
13053        };
13054
13055        $scope.updateModel = function(method, url) {
13056          $scope.method = method;
13057          $scope.url = url;
13058        };
13059      }]);
13060</file>
13061<file name="http-hello.html">
13062  Hello, $http!
13063</file>
13064<file name="protractor.js" type="protractor">
13065  var status = element(by.binding('status'));
13066  var data = element(by.binding('data'));
13067  var fetchBtn = element(by.id('fetchbtn'));
13068  var sampleGetBtn = element(by.id('samplegetbtn'));
13069  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
13070  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
13071
13072  it('should make an xhr GET request', function() {
13073    sampleGetBtn.click();
13074    fetchBtn.click();
13075    expect(status.getText()).toMatch('200');
13076    expect(data.getText()).toMatch(/Hello, \$http!/);
13077  });
13078
13079  it('should make a JSONP request to angularjs.org', function() {
13080    sampleJsonpBtn.click();
13081    fetchBtn.click();
13082    expect(status.getText()).toMatch('200');
13083    expect(data.getText()).toMatch(/Super Hero!/);
13084  });
13085
13086  it('should make JSONP request to invalid URL and invoke the error handler',
13087      function() {
13088    invalidJsonpBtn.click();
13089    fetchBtn.click();
13090    expect(status.getText()).toMatch('0');
13091    expect(data.getText()).toMatch('Request failed');
13092  });
13093</file>
13094</example>
13095     */
13096    function $http(requestConfig) {
13097      var config = {
13098        method: 'get',
13099        transformRequest: defaults.transformRequest,
13100        transformResponse: defaults.transformResponse
13101      };
13102      var headers = mergeHeaders(requestConfig);
13103
13104      extend(config, requestConfig);
13105      config.headers = headers;
13106      config.method = uppercase(config.method);
13107
13108      var serverRequest = function(config) {
13109        headers = config.headers;
13110        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
13111
13112        // strip content-type if data is undefined
13113        if (isUndefined(reqData)) {
13114          forEach(headers, function(value, header) {
13115            if (lowercase(header) === 'content-type') {
13116                delete headers[header];
13117            }
13118          });
13119        }
13120
13121        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
13122          config.withCredentials = defaults.withCredentials;
13123        }
13124
13125        // send request
13126        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
13127      };
13128
13129      var chain = [serverRequest, undefined];
13130      var promise = $q.when(config);
13131
13132      // apply interceptors
13133      forEach(reversedInterceptors, function(interceptor) {
13134        if (interceptor.request || interceptor.requestError) {
13135          chain.unshift(interceptor.request, interceptor.requestError);
13136        }
13137        if (interceptor.response || interceptor.responseError) {
13138          chain.push(interceptor.response, interceptor.responseError);
13139        }
13140      });
13141
13142      while(chain.length) {
13143        var thenFn = chain.shift();
13144        var rejectFn = chain.shift();
13145
13146        promise = promise.then(thenFn, rejectFn);
13147      }
13148
13149      promise.success = function(fn) {
13150        promise.then(function(response) {
13151          fn(response.data, response.status, response.headers, config);
13152        });
13153        return promise;
13154      };
13155
13156      promise.error = function(fn) {
13157        promise.then(null, function(response) {
13158          fn(response.data, response.status, response.headers, config);
13159        });
13160        return promise;
13161      };
13162
13163      return promise;
13164
13165      function transformResponse(response) {
13166        // make a copy since the response must be cacheable
13167        var resp = extend({}, response, {
13168          data: transformData(response.data, response.headers, config.transformResponse)
13169        });
13170        return (isSuccess(response.status))
13171          ? resp
13172          : $q.reject(resp);
13173      }
13174
13175      function mergeHeaders(config) {
13176        var defHeaders = defaults.headers,
13177            reqHeaders = extend({}, config.headers),
13178            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
13179
13180        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
13181
13182        // using for-in instead of forEach to avoid unecessary iteration after header has been found
13183        defaultHeadersIteration:
13184        for (defHeaderName in defHeaders) {
13185          lowercaseDefHeaderName = lowercase(defHeaderName);
13186
13187          for (reqHeaderName in reqHeaders) {
13188            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
13189              continue defaultHeadersIteration;
13190            }
13191          }
13192
13193          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
13194        }
13195
13196        // execute if header value is a function for merged headers
13197        execHeaders(reqHeaders);
13198        return reqHeaders;
13199
13200        function execHeaders(headers) {
13201          var headerContent;
13202
13203          forEach(headers, function(headerFn, header) {
13204            if (isFunction(headerFn)) {
13205              headerContent = headerFn();
13206              if (headerContent != null) {
13207                headers[header] = headerContent;
13208              } else {
13209                delete headers[header];
13210              }
13211            }
13212          });
13213        }
13214      }
13215    }
13216
13217    $http.pendingRequests = [];
13218
13219    /**
13220     * @ngdoc method
13221     * @name $http#get
13222     *
13223     * @description
13224     * Shortcut method to perform `GET` request.
13225     *
13226     * @param {string} url Relative or absolute URL specifying the destination of the request
13227     * @param {Object=} config Optional configuration object
13228     * @returns {HttpPromise} Future object
13229     */
13230
13231    /**
13232     * @ngdoc method
13233     * @name $http#delete
13234     *
13235     * @description
13236     * Shortcut method to perform `DELETE` request.
13237     *
13238     * @param {string} url Relative or absolute URL specifying the destination of the request
13239     * @param {Object=} config Optional configuration object
13240     * @returns {HttpPromise} Future object
13241     */
13242
13243    /**
13244     * @ngdoc method
13245     * @name $http#head
13246     *
13247     * @description
13248     * Shortcut method to perform `HEAD` request.
13249     *
13250     * @param {string} url Relative or absolute URL specifying the destination of the request
13251     * @param {Object=} config Optional configuration object
13252     * @returns {HttpPromise} Future object
13253     */
13254
13255    /**
13256     * @ngdoc method
13257     * @name $http#jsonp
13258     *
13259     * @description
13260     * Shortcut method to perform `JSONP` request.
13261     *
13262     * @param {string} url Relative or absolute URL specifying the destination of the request.
13263     *                     The name of the callback should be the string `JSON_CALLBACK`.
13264     * @param {Object=} config Optional configuration object
13265     * @returns {HttpPromise} Future object
13266     */
13267    createShortMethods('get', 'delete', 'head', 'jsonp');
13268
13269    /**
13270     * @ngdoc method
13271     * @name $http#post
13272     *
13273     * @description
13274     * Shortcut method to perform `POST` request.
13275     *
13276     * @param {string} url Relative or absolute URL specifying the destination of the request
13277     * @param {*} data Request content
13278     * @param {Object=} config Optional configuration object
13279     * @returns {HttpPromise} Future object
13280     */
13281
13282    /**
13283     * @ngdoc method
13284     * @name $http#put
13285     *
13286     * @description
13287     * Shortcut method to perform `PUT` request.
13288     *
13289     * @param {string} url Relative or absolute URL specifying the destination of the request
13290     * @param {*} data Request content
13291     * @param {Object=} config Optional configuration object
13292     * @returns {HttpPromise} Future object
13293     */
13294    createShortMethodsWithData('post', 'put');
13295
13296        /**
13297         * @ngdoc property
13298         * @name $http#defaults
13299         *
13300         * @description
13301         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
13302         * default headers, withCredentials as well as request and response transformations.
13303         *
13304         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
13305         */
13306    $http.defaults = defaults;
13307
13308
13309    return $http;
13310
13311
13312    function createShortMethods(names) {
13313      forEach(arguments, function(name) {
13314        $http[name] = function(url, config) {
13315          return $http(extend(config || {}, {
13316            method: name,
13317            url: url
13318          }));
13319        };
13320      });
13321    }
13322
13323
13324    function createShortMethodsWithData(name) {
13325      forEach(arguments, function(name) {
13326        $http[name] = function(url, data, config) {
13327          return $http(extend(config || {}, {
13328            method: name,
13329            url: url,
13330            data: data
13331          }));
13332        };
13333      });
13334    }
13335
13336
13337    /**
13338     * Makes the request.
13339     *
13340     * !!! ACCESSES CLOSURE VARS:
13341     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
13342     */
13343    function sendReq(config, reqData, reqHeaders) {
13344      var deferred = $q.defer(),
13345          promise = deferred.promise,
13346          cache,
13347          cachedResp,
13348          url = buildUrl(config.url, config.params);
13349
13350      $http.pendingRequests.push(config);
13351      promise.then(removePendingReq, removePendingReq);
13352
13353
13354      if ((config.cache || defaults.cache) && config.cache !== false &&
13355          (config.method === 'GET' || config.method === 'JSONP')) {
13356        cache = isObject(config.cache) ? config.cache
13357              : isObject(defaults.cache) ? defaults.cache
13358              : defaultCache;
13359      }
13360
13361      if (cache) {
13362        cachedResp = cache.get(url);
13363        if (isDefined(cachedResp)) {
13364          if (isPromiseLike(cachedResp)) {
13365            // cached request has already been sent, but there is no response yet
13366            cachedResp.then(removePendingReq, removePendingReq);
13367            return cachedResp;
13368          } else {
13369            // serving from cache
13370            if (isArray(cachedResp)) {
13371              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
13372            } else {
13373              resolvePromise(cachedResp, 200, {}, 'OK');
13374            }
13375          }
13376        } else {
13377          // put the promise for the non-transformed response into cache as a placeholder
13378          cache.put(url, promise);
13379        }
13380      }
13381
13382
13383      // if we won't have the response in cache, set the xsrf headers and
13384      // send the request to the backend
13385      if (isUndefined(cachedResp)) {
13386        var xsrfValue = urlIsSameOrigin(config.url)
13387            ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
13388            : undefined;
13389        if (xsrfValue) {
13390          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
13391        }
13392
13393        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
13394            config.withCredentials, config.responseType);
13395      }
13396
13397      return promise;
13398
13399
13400      /**
13401       * Callback registered to $httpBackend():
13402       *  - caches the response if desired
13403       *  - resolves the raw $http promise
13404       *  - calls $apply
13405       */
13406      function done(status, response, headersString, statusText) {
13407        if (cache) {
13408          if (isSuccess(status)) {
13409            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
13410          } else {
13411            // remove promise from the cache
13412            cache.remove(url);
13413          }
13414        }
13415
13416        resolvePromise(response, status, headersString, statusText);
13417        if (!$rootScope.$$phase) $rootScope.$apply();
13418      }
13419
13420
13421      /**
13422       * Resolves the raw $http promise.
13423       */
13424      function resolvePromise(response, status, headers, statusText) {
13425        // normalize internal statuses to 0
13426        status = Math.max(status, 0);
13427
13428        (isSuccess(status) ? deferred.resolve : deferred.reject)({
13429          data: response,
13430          status: status,
13431          headers: headersGetter(headers),
13432          config: config,
13433          statusText : statusText
13434        });
13435      }
13436
13437
13438      function removePendingReq() {
13439        var idx = indexOf($http.pendingRequests, config);
13440        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
13441      }
13442    }
13443
13444
13445    function buildUrl(url, params) {
13446      if (!params) return url;
13447      var parts = [];
13448      forEachSorted(params, function(value, key) {
13449        if (value === null || isUndefined(value)) return;
13450        if (!isArray(value)) value = [value];
13451
13452        forEach(value, function(v) {
13453          if (isObject(v)) {
13454            if (isDate(v)){
13455              v = v.toISOString();
13456            } else {
13457              v = toJson(v);
13458            }
13459          }
13460          parts.push(encodeUriQuery(key) + '=' +
13461                     encodeUriQuery(v));
13462        });
13463      });
13464      if(parts.length > 0) {
13465        url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
13466      }
13467      return url;
13468    }
13469  }];
13470}
13471
13472function createXhr(method) {
13473    //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
13474    //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
13475    //if it is available
13476    if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
13477      !window.XMLHttpRequest)) {
13478      return new window.ActiveXObject("Microsoft.XMLHTTP");
13479    } else if (window.XMLHttpRequest) {
13480      return new window.XMLHttpRequest();
13481    }
13482
13483    throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
13484}
13485
13486/**
13487 * @ngdoc service
13488 * @name $httpBackend
13489 * @requires $window
13490 * @requires $document
13491 *
13492 * @description
13493 * HTTP backend used by the {@link ng.$http service} that delegates to
13494 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
13495 *
13496 * You should never need to use this service directly, instead use the higher-level abstractions:
13497 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
13498 *
13499 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
13500 * $httpBackend} which can be trained with responses.
13501 */
13502function $HttpBackendProvider() {
13503  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
13504    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
13505  }];
13506}
13507
13508function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
13509  var ABORTED = -1;
13510
13511  // TODO(vojta): fix the signature
13512  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
13513    var status;
13514    $browser.$$incOutstandingRequestCount();
13515    url = url || $browser.url();
13516
13517    if (lowercase(method) == 'jsonp') {
13518      var callbackId = '_' + (callbacks.counter++).toString(36);
13519      callbacks[callbackId] = function(data) {
13520        callbacks[callbackId].data = data;
13521        callbacks[callbackId].called = true;
13522      };
13523
13524      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
13525          callbackId, function(status, text) {
13526        completeRequest(callback, status, callbacks[callbackId].data, "", text);
13527        callbacks[callbackId] = noop;
13528      });
13529    } else {
13530
13531      var xhr = createXhr(method);
13532
13533      xhr.open(method, url, true);
13534      forEach(headers, function(value, key) {
13535        if (isDefined(value)) {
13536            xhr.setRequestHeader(key, value);
13537        }
13538      });
13539
13540      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
13541      // response is in the cache. the promise api will ensure that to the app code the api is
13542      // always async
13543      xhr.onreadystatechange = function() {
13544        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
13545        // xhrs that are resolved while the app is in the background (see #5426).
13546        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
13547        // continuing
13548        //
13549        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
13550        // Safari respectively.
13551        if (xhr && xhr.readyState == 4) {
13552          var responseHeaders = null,
13553              response = null,
13554              statusText = '';
13555
13556          if(status !== ABORTED) {
13557            responseHeaders = xhr.getAllResponseHeaders();
13558
13559            // responseText is the old-school way of retrieving response (supported by IE8 & 9)
13560            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
13561            response = ('response' in xhr) ? xhr.response : xhr.responseText;
13562          }
13563
13564          // Accessing statusText on an aborted xhr object will
13565          // throw an 'c00c023f error' in IE9 and lower, don't touch it.
13566          if (!(status === ABORTED && msie < 10)) {
13567            statusText = xhr.statusText;
13568          }
13569
13570          completeRequest(callback,
13571              status || xhr.status,
13572              response,
13573              responseHeaders,
13574              statusText);
13575        }
13576      };
13577
13578      if (withCredentials) {
13579        xhr.withCredentials = true;
13580      }
13581
13582      if (responseType) {
13583        try {
13584          xhr.responseType = responseType;
13585        } catch (e) {
13586          // WebKit added support for the json responseType value on 09/03/2013
13587          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
13588          // known to throw when setting the value "json" as the response type. Other older
13589          // browsers implementing the responseType
13590          //
13591          // The json response type can be ignored if not supported, because JSON payloads are
13592          // parsed on the client-side regardless.
13593          if (responseType !== 'json') {
13594            throw e;
13595          }
13596        }
13597      }
13598
13599      xhr.send(post || null);
13600    }
13601
13602    if (timeout > 0) {
13603      var timeoutId = $browserDefer(timeoutRequest, timeout);
13604    }
13604 else if (isPromiseLike(timeout)) {
13605      timeout.then(timeoutRequest);
13606    }
13607
13608
13609    function timeoutRequest() {
13610      status = ABORTED;
13611      jsonpDone && jsonpDone();
13612      xhr && xhr.abort();
13613    }
13614
13615    function completeRequest(callback, status, response, headersString, statusText) {
13616      // cancel timeout and subsequent timeout promise resolution
13617      timeoutId && $browserDefer.cancel(timeoutId);
13618      jsonpDone = xhr = null;
13619
13620      // fix status code when it is 0 (0 status is undocumented).
13621      // Occurs when accessing file resources or on Android 4.1 stock browser
13622      // while retrieving files from application cache.
13623      if (status === 0) {
13624        status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
13625      }
13626
13627      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
13628      status = status === 1223 ? 204 : status;
13629      statusText = statusText || '';
13630
13631      callback(status, response, headersString, statusText);
13632      $browser.$$completeOutstandingRequest(noop);
13633    }
13634  };
13635
13636  function jsonpReq(url, callbackId, done) {
13637    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
13638    // - fetches local scripts via XHR and evals them
13639    // - adds and immediately removes script elements from the document
13640    var script = rawDocument.createElement('script'), callback = null;
13641    script.type = "text/javascript";
13642    script.src = url;
13643    script.async = true;
13644
13645    callback = function(event) {
13646      removeEventListenerFn(script, "load", callback);
13647      removeEventListenerFn(script, "error", callback);
13648      rawDocument.body.removeChild(script);
13649      script = null;
13650      var status = -1;
13651      var text = "unknown";
13652
13653      if (event) {
13654        if (event.type === "load" && !callbacks[callbackId].called) {
13655          event = { type: "error" };
13656        }
13657        text = event.type;
13658        status = event.type === "error" ? 404 : 200;
13659      }
13660
13661      if (done) {
13662        done(status, text);
13663      }
13664    };
13665
13666    addEventListenerFn(script, "load", callback);
13667    addEventListenerFn(script, "error", callback);
13668
13669    if (msie <= 8) {
13670      script.onreadystatechange = function() {
13671        if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) {
13672          script.onreadystatechange = null;
13673          callback({
13674            type: 'load'
13675          });
13676        }
13677      };
13678    }
13679
13680    rawDocument.body.appendChild(script);
13681    return callback;
13682  }
13683}
13684
13685var $interpolateMinErr = minErr('$interpolate');
13686
13687/**
13688 * @ngdoc provider
13689 * @name $interpolateProvider
13690 * @kind function
13691 *
13692 * @description
13693 *
13694 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
13695 *
13696 * @example
13697<example module="customInterpolationApp">
13698<file name="index.html">
13699<script>
13700  var customInterpolationApp = angular.module('customInterpolationApp', []);
13701
13702  customInterpolationApp.config(function($interpolateProvider) {
13703    $interpolateProvider.startSymbol('//');
13704    $interpolateProvider.endSymbol('//');
13705  });
13706
13707
13708  customInterpolationApp.controller('DemoController', function() {
13709      this.label = "This binding is brought you by // interpolation symbols.";
13710  });
13711</script>
13712<div ng-app="App" ng-controller="DemoController as demo">
13713    //demo.label//
13714</div>
13715</file>
13716<file name="protractor.js" type="protractor">
13717  it('should interpolate binding with custom symbols', function() {
13718    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
13719  });
13720</file>
13721</example>
13722 */
13723function $InterpolateProvider() {
13724  var startSymbol = '{{';
13725  var endSymbol = '}}';
13726
13727  /**
13728   * @ngdoc method
13729   * @name $interpolateProvider#startSymbol
13730   * @description
13731   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
13732   *
13733   * @param {string=} value new value to set the starting symbol to.
13734   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
13735   */
13736  this.startSymbol = function(value){
13737    if (value) {
13738      startSymbol = value;
13739      return this;
13740    } else {
13741      return startSymbol;
13742    }
13743  };
13744
13745  /**
13746   * @ngdoc method
13747   * @name $interpolateProvider#endSymbol
13748   * @description
13749   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
13750   *
13751   * @param {string=} value new value to set the ending symbol to.
13752   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
13753   */
13754  this.endSymbol = function(value){
13755    if (value) {
13756      endSymbol = value;
13757      return this;
13758    } else {
13759      return endSymbol;
13760    }
13761  };
13762
13763
13764  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
13765    var startSymbolLength = startSymbol.length,
13766        endSymbolLength = endSymbol.length;
13767
13768    /**
13769     * @ngdoc service
13770     * @name $interpolate
13771     * @kind function
13772     *
13773     * @requires $parse
13774     * @requires $sce
13775     *
13776     * @description
13777     *
13778     * Compiles a string with markup into an interpolation function. This service is used by the
13779     * HTML {@link ng.$compile $compile} service for data binding. See
13780     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
13781     * interpolation markup.
13782     *
13783     *
13784     * ```js
13785     *   var $interpolate = ...; // injected
13786     *   var exp = $interpolate('Hello {{name | uppercase}}!');
13787     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
13788     * ```
13789     *
13790     *
13791     * @param {string} text The text with markup to interpolate.
13792     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
13793     *    embedded expression in order to return an interpolation function. Strings with no
13794     *    embedded expression will return null for the interpolation function.
13795     * @param {string=} trustedContext when provided, the returned function passes the interpolated
13796     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
13797     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
13798     *    provides Strict Contextual Escaping for details.
13799     * @returns {function(context)} an interpolation function which is used to compute the
13800     *    interpolated string. The function has these parameters:
13801     *
13802     *    * `context`: an object against which any expressions embedded in the strings are evaluated
13803     *      against.
13804     *
13805     */
13806    function $interpolate(text, mustHaveExpression, trustedContext) {
13807      var startIndex,
13808          endIndex,
13809          index = 0,
13810          parts = [],
13811          length = text.length,
13812          hasInterpolation = false,
13813          fn,
13814          exp,
13815          concat = [];
13816
13817      while(index < length) {
13818        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
13819             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
13820          (index != startIndex) && parts.push(text.substring(index, startIndex));
13821          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
13822          fn.exp = exp;
13823          index = endIndex + endSymbolLength;
13824          hasInterpolation = true;
13825        } else {
13826          // we did not find anything, so we have to add the remainder to the parts array
13827          (index != length) && parts.push(text.substring(index));
13828          index = length;
13829        }
13830      }
13831
13832      if (!(length = parts.length)) {
13833        // we added, nothing, must have been an empty string.
13834        parts.push('');
13835        length = 1;
13836      }
13837
13838      // Concatenating expressions makes it hard to reason about whether some combination of
13839      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
13840      // single expression be used for iframe[src], object[src], etc., we ensure that the value
13841      // that's used is assigned or constructed by some JS code somewhere that is more testable or
13842      // make it obvious that you bound the value to some user controlled value.  This helps reduce
13843      // the load when auditing for XSS issues.
13844      if (trustedContext && parts.length > 1) {
13845          throw $interpolateMinErr('noconcat',
13846              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
13847              "interpolations that concatenate multiple expressions when a trusted value is " +
13848              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
13849      }
13850
13851      if (!mustHaveExpression  || hasInterpolation) {
13852        concat.length = length;
13853        fn = function(context) {
13854          try {
13855            for(var i = 0, ii = length, part; i<ii; i++) {
13856              if (typeof (part = parts[i]) == 'function') {
13857                part = part(context);
13858                if (trustedContext) {
13859                  part = $sce.getTrusted(trustedContext, part);
13860                } else {
13861                  part = $sce.valueOf(part);
13862                }
13863                if (part == null) { // null || undefined
13864                  part = '';
13865                } else {
13866                  switch (typeof part) {
13867                    case 'string':
13868                    {
13869                      break;
13870                    }
13871                    case 'number':
13872                    {
13873                      part = '' + part;
13874                      break;
13875                    }
13876                    default:
13877                    {
13878                      part = toJson(part);
13879                    }
13880                  }
13881                }
13882              }
13883              concat[i] = part;
13884            }
13885            return concat.join('');
13886          }
13887          catch(err) {
13888            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
13889                err.toString());
13890            $exceptionHandler(newErr);
13891          }
13892        };
13893        fn.exp = text;
13894        fn.parts = parts;
13895        return fn;
13896      }
13897    }
13898
13899
13900    /**
13901     * @ngdoc method
13902     * @name $interpolate#startSymbol
13903     * @description
13904     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
13905     *
13906     * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
13907     * the symbol.
13908     *
13909     * @returns {string} start symbol.
13910     */
13911    $interpolate.startSymbol = function() {
13912      return startSymbol;
13913    };
13914
13915
13916    /**
13917     * @ngdoc method
13918     * @name $interpolate#endSymbol
13919     * @description
13920     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
13921     *
13922     * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
13923     * the symbol.
13924     *
13925     * @returns {string} end symbol.
13926     */
13927    $interpolate.endSymbol = function() {
13928      return endSymbol;
13929    };
13930
13931    return $interpolate;
13932  }];
13933}
13934
13935function $IntervalProvider() {
13936  this.$get = ['$rootScope', '$window', '$q',
13937       function($rootScope,   $window,   $q) {
13938    var intervals = {};
13939
13940
13941     /**
13942      * @ngdoc service
13943      * @name $interval
13944      *
13945      * @description
13946      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
13947      * milliseconds.
13948      *
13949      * The return value of registering an interval function is a promise. This promise will be
13950      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
13951      * run indefinitely if `count` is not defined. The value of the notification will be the
13952      * number of iterations that have run.
13953      * To cancel an interval, call `$interval.cancel(promise)`.
13954      *
13955      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
13956      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
13957      * time.
13958      *
13959      * <div class="alert alert-warning">
13960      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
13961      * with them.  In particular they are not automatically destroyed when a controller's scope or a
13962      * directive's element are destroyed.
13963      * You should take this into consideration and make sure to always cancel the interval at the
13964      * appropriate moment.  See the example below for more details on how and when to do this.
13965      * </div>
13966      *
13967      * @param {function()} fn A function that should be called repeatedly.
13968      * @param {number} delay Number of milliseconds between each function call.
13969      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
13970      *   indefinitely.
13971      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
13972      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
13973      * @returns {promise} A promise which will be notified on each iteration.
13974      *
13975      * @example
13976      * <example module="intervalExample">
13977      * <file name="index.html">
13978      *   <script>
13979      *     angular.module('intervalExample', [])
13980      *       .controller('ExampleController', ['$scope', '$interval',
13981      *         function($scope, $interval) {
13982      *           $scope.format = 'M/d/yy h:mm:ss a';
13983      *           $scope.blood_1 = 100;
13984      *           $scope.blood_2 = 120;
13985      *
13986      *           var stop;
13987      *           $scope.fight = function() {
13988      *             // Don't start a new fight if we are already fighting
13989      *             if ( angular.isDefined(stop) ) return;
13990      *
13991      *           stop = $interval(function() {
13992      *             if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
13993      *               $scope.blood_1 = $scope.blood_1 - 3;
13994      *               $scope.blood_2 = $scope.blood_2 - 4;
13995      *             } else {
13996      *               $scope.stopFight();
13997      *             }
13998      *           }, 100);
13999      *         };
14000      *
14001      *         $scope.stopFight = function() {
14002      *           if (angular.isDefined(stop)) {
14003      *             $interval.cancel(stop);
14004      *             stop = undefined;
14005      *           }
14006      *         };
14007      *
14008      *         $scope.resetFight = function() {
14009      *           $scope.blood_1 = 100;
14010      *           $scope.blood_2 = 120;
14011      *         };
14012      *
14013      *         $scope.$on('$destroy', function() {
14014      *           // Make sure that the interval is destroyed too
14015      *           $scope.stopFight();
14016      *         });
14017      *       }])
14018      *       // Register the 'myCurrentTime' directive factory method.
14019      *       // We inject $interval and dateFilter service since the factory method is DI.
14020      *       .directive('myCurrentTime', ['$interval', 'dateFilter',
14021      *         function($interval, dateFilter) {
14022      *           // return the directive link function. (compile function not needed)
14023      *           return function(scope, element, attrs) {
14024      *             var format,  // date format
14025      *                 stopTime; // so that we can cancel the time updates
14026      *
14027      *             // used to update the UI
14028      *             function updateTime() {
14029      *               element.text(dateFilter(new Date(), format));
14030      *             }
14031      *
14032      *             // watch the expression, and update the UI on change.
14033      *             scope.$watch(attrs.myCurrentTime, function(value) {
14034      *               format = value;
14035      *               updateTime();
14036      *             });
14037      *
14038      *             stopTime = $interval(updateTime, 1000);
14039      *
14040      *             // listen on DOM destroy (removal) event, and cancel the next UI update
14041      *             // to prevent updating time after the DOM element was removed.
14042      *             element.bind('$destroy', function() {
14043      *               $interval.cancel(stopTime);
14044      *             });
14045      *           }
14046      *         }]);
14047      *   </script>
14048      *
14049      *   <div>
14050      *     <div ng-controller="ExampleController">
14051      *       Date format: <input ng-model="format"> <hr/>
14052      *       Current time is: <span my-current-time="format"></span>
14053      *       <hr/>
14054      *       Blood 1 : <font color='red'>{{blood_1}}</font>
14055      *       Blood 2 : <font color='red'>{{blood_2}}</font>
14056      *       <button type="button" data-ng-click="fight()">Fight</button>
14057      *       <button type="button" data-ng-click="stopFight()">StopFight</button>
14058      *       <button type="button" data-ng-click="resetFight()">resetFight</button>
14059      *     </div>
14060      *   </div>
14061      *
14062      * </file>
14063      * </example>
14064      */
14065    function interval(fn, delay, count, invokeApply) {
14066      var setInterval = $window.setInterval,
14067          clearInterval = $window.clearInterval,
14068          deferred = $q.defer(),
14069          promise = deferred.promise,
14070          iteration = 0,
14071          skipApply = (isDefined(invokeApply) && !invokeApply);
14072
14073      count = isDefined(count) ? count : 0;
14074
14075      promise.then(null, null, fn);
14076
14077      promise.$$intervalId = setInterval(function tick() {
14078        deferred.notify(iteration++);
14079
14080        if (count > 0 && iteration >= count) {
14081          deferred.resolve(iteration);
14082          clearInterval(promise.$$intervalId);
14083          delete intervals[promise.$$intervalId];
14084        }
14085
14086        if (!skipApply) $rootScope.$apply();
14087
14088      }, delay);
14089
14090      intervals[promise.$$intervalId] = deferred;
14091
14092      return promise;
14093    }
14094
14095
14096     /**
14097      * @ngdoc method
14098      * @name $interval#cancel
14099      *
14100      * @description
14101      * Cancels a task associated with the `promise`.
14102      *
14103      * @param {promise} promise returned by the `$interval` function.
14104      * @returns {boolean} Returns `true` if the task was successfully canceled.
14105      */
14106    interval.cancel = function(promise) {
14107      if (promise && promise.$$intervalId in intervals) {
14108        intervals[promise.$$intervalId].reject('canceled');
14109        $window.clearInterval(promise.$$intervalId);
14110        delete intervals[promise.$$intervalId];
14111        return true;
14112      }
14113      return false;
14114    };
14115
14116    return interval;
14117  }];
14118}
14119
14120/**
14121 * @ngdoc service
14122 * @name $locale
14123 *
14124 * @description
14125 * $locale service provides localization rules for various Angular components. As of right now the
14126 * only public api is:
14127 *
14128 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
14129 */
14130function $LocaleProvider(){
14131  this.$get = function() {
14132    return {
14133      id: 'en-us',
14134
14135      NUMBER_FORMATS: {
14136        DECIMAL_SEP: '.',
14137        GROUP_SEP: ',',
14138        PATTERNS: [
14139          { // Decimal Pattern
14140            minInt: 1,
14141            minFrac: 0,
14142            maxFrac: 3,
14143            posPre: '',
14144            posSuf: '',
14145            negPre: '-',
14146            negSuf: '',
14147            gSize: 3,
14148            lgSize: 3
14149          },{ //Currency Pattern
14150            minInt: 1,
14151            minFrac: 2,
14152            maxFrac: 2,
14153            posPre: '\u00A4',
14154            posSuf: '',
14155            negPre: '(\u00A4',
14156            negSuf: ')',
14157            gSize: 3,
14158            lgSize: 3
14159          }
14160        ],
14161        CURRENCY_SYM: '$'
14162      },
14163
14164      DATETIME_FORMATS: {
14165        MONTH:
14166            'January,February,March,April,May,June,July,August,September,October,November,December'
14167            .split(','),
14168        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
14169        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
14170        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
14171        AMPMS: ['AM','PM'],
14172        medium: 'MMM d, y h:mm:ss a',
14173        short: 'M/d/yy h:mm a',
14174        fullDate: 'EEEE, MMMM d, y',
14175        longDate: 'MMMM d, y',
14176        mediumDate: 'MMM d, y',
14177        shortDate: 'M/d/yy',
14178        mediumTime: 'h:mm:ss a',
14179        shortTime: 'h:mm a'
14180      },
14181
14182      pluralCat: function(num) {
14183        if (num === 1) {
14184          return 'one';
14185        }
14186        return 'other';
14187      }
14188    };
14189  };
14190}
14191
14192var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
14193    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
14194var $locationMinErr = minErr('$location');
14195
14196
14197/**
14198 * Encode path using encodeUriSegment, ignoring forward slashes
14199 *
14200 * @param {string} path Path to encode
14201 * @returns {string}
14202 */
14203function encodePath(path) {
14204  var segments = path.split('/'),
14205      i = segments.length;
14206
14207  while (i--) {
14208    segments[i] = encodeUriSegment(segments[i]);
14209  }
14210
14211  return segments.join('/');
14212}
14213
14214function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
14215  var parsedUrl = urlResolve(absoluteUrl, appBase);
14216
14217  locationObj.$$protocol = parsedUrl.protocol;
14218  locationObj.$$host = parsedUrl.hostname;
14219  locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
14220}
14221
14222
14223function parseAppUrl(relativeUrl, locationObj, appBase) {
14224  var prefixed = (relativeUrl.charAt(0) !== '/');
14225  if (prefixed) {
14226    relativeUrl = '/' + relativeUrl;
14227  }
14228  var match = urlResolve(relativeUrl, appBase);
14229  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
14230      match.pathname.substring(1) : match.pathname);
14231  locationObj.$$search = parseKeyValue(match.search);
14232  locationObj.$$hash = decodeURIComponent(match.hash);
14233
14234  // make sure path starts with '/';
14235  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
14236    locationObj.$$path = '/' + locationObj.$$path;
14237  }
14238}
14239
14240
14241/**
14242 *
14243 * @param {string} begin
14244 * @param {string} whole
14245 * @returns {string} returns text from whole after begin or undefined if it does not begin with
14246 *                   expected string.
14247 */
14248function beginsWith(begin, whole) {
14249  if (whole.indexOf(begin) === 0) {
14250    return whole.substr(begin.length);
14251  }
14252}
14253
14254
14255function stripHash(url) {
14256  var index = url.indexOf('#');
14257  return index == -1 ? url : url.substr(0, index);
14258}
14259
14260
14261function stripFile(url) {
14262  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
14263}
14264
14265/* return the server only (scheme://host:port) */
14266function serverBase(url) {
14267  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
14268}
14269
14270
14271/**
14272 * LocationHtml5Url represents an url
14273 * This object is exposed as $location service when HTML5 mode is enabled and supported
14274 *
14275 * @constructor
14276 * @param {string} appBase application base URL
14277 * @param {string} basePrefix url path prefix
14278 */
14279function LocationHtml5Url(appBase, basePrefix) {
14280  this.$$html5 = true;
14281  basePrefix = basePrefix || '';
14282  var appBaseNoFile = stripFile(appBase);
14283  parseAbsoluteUrl(appBase, this, appBase);
14284
14285
14286  /**
14287   * Parse given html5 (regular) url string into properties
14288   * @param {string} newAbsoluteUrl HTML5 url
14289   * @private
14290   */
14291  this.$$parse = function(url) {
14292    var pathUrl = beginsWith(appBaseNoFile, url);
14293    if (!isString(pathUrl)) {
14294      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
14295          appBaseNoFile);
14296    }
14297
14298    parseAppUrl(pathUrl, this, appBase);
14299
14300    if (!this.$$path) {
14301      this.$$path = '/';
14302    }
14303
14304    this.$$compose();
14305  };
14306
14307  /**
14308   * Compose url and update `absUrl` property
14309   * @private
14310   */
14311  this.$$compose = function() {
14312    var search = toKeyValue(this.$$search),
14313        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
14314
14315    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
14316    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
14317  };
14318
14319  this.$$rewrite = function(url) {
14320    var appUrl, prevAppUrl;
14321
14322    if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
14323      prevAppUrl = appUrl;
14324      if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
14325        return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
14326      } else {
14327        return appBase + prevAppUrl;
14328      }
14329    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
14330      return appBaseNoFile + appUrl;
14331    } else if (appBaseNoFile == url + '/') {
14332      return appBaseNoFile;
14333    }
14334  };
14335}
14336
14337
14338/**
14339 * LocationHashbangUrl represents url
14340 * This object is exposed as $location service when developer doesn't opt into html5 mode.
14341 * It also serves as the base class for html5 mode fallback on legacy browsers.
14342 *
14343 * @constructor
14344 * @param {string} appBase application base URL
14345 * @param {string} hashPrefix hashbang prefix
14346 */
14347function LocationHashbangUrl(appBase, hashPrefix) {
14348  var appBaseNoFile = stripFile(appBase);
14349
14350  parseAbsoluteUrl(appBase, this, appBase);
14351
14352
14353  /**
14354   * Parse given hashbang url into properties
14355   * @param {string} url Hashbang url
14356   * @private
14357   */
14358  this.$$parse = function(url) {
14359    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
14360    var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
14361        ? beginsWith(hashPrefix, withoutBaseUrl)
14362        : (this.$$html5)
14363          ? withoutBaseUrl
14364          : '';
14365
14366    if (!isString(withoutHashUrl)) {
14367      throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
14368          hashPrefix);
14369    }
14370    parseAppUrl(withoutHashUrl, this, appBase);
14371
14372    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
14373
14374    this.$$compose();
14375
14376    /*
14377     * In Windows, on an anchor node on documents loaded from
14378     * the filesystem, the browser will return a pathname
14379     * prefixed with the drive name ('/C:/path') when a
14380     * pathname without a drive is set:
14381     *  * a.setAttribute('href', '/foo')
14382     *   * a.pathname === '/C:/foo' //true
14383     *
14384     * Inside of Angular, we're always using pathnames that
14385     * do not include drive names for routing.
14386     */
14387    function removeWindowsDriveName (path, url, base) {
14388      /*
14389      Matches paths for file protocol on windows,
14390      such as /C:/foo/bar, and captures only /foo/bar.
14391      */
14392      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
14393
14394      var firstPathSegmentMatch;
14395
14396      //Get the relative path from the input URL.
14397      if (url.indexOf(base) === 0) {
14398        url = url.replace(base, '');
14399      }
14400
14401      // The input URL intentionally contains a first path segment that ends with a colon.
14402      if (windowsFilePathExp.exec(url)) {
14403        return path;
14404      }
14405
14406      firstPathSegmentMatch = windowsFilePathExp.exec(path);
14407      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
14408    }
14409  };
14410
14411  /**
14412   * Compose hashbang url and update `absUrl` property
14413   * @private
14414   */
14415  this.$$compose = function() {
14416    var search = toKeyValue(this.$$search),
14417        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
14418
14419    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
14420    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
14421  };
14422
14423  this.$$rewrite = function(url) {
14424    if(stripHash(appBase) == stripHash(url)) {
14425      return url;
14426    }
14427  };
14428}
14429
14430
14431/**
14432 * LocationHashbangUrl represents url
14433 * This object is exposed as $location service when html5 history api is enabled but the browser
14434 * does not support it.
14435 *
14436 * @constructor
14437 * @param {string} appBase application base URL
14438 * @param {string} hashPrefix hashbang prefix
14439 */
14440function LocationHashbangInHtml5Url(appBase, hashPrefix) {
14441  this.$$html5 = true;
14442  LocationHashbangUrl.apply(this, arguments);
14443
14444  var appBaseNoFile = stripFile(appBase);
14445
14446  this.$$rewrite = function(url) {
14447    var appUrl;
14448
14449    if ( appBase == stripHash(url) ) {
14450      return url;
14451    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
14452      return appBase + hashPrefix + appUrl;
14453    } else if ( appBaseNoFile === url + '/') {
14454      return appBaseNoFile;
14455    }
14456  };
14457
14458  this.$$compose = function() {
14459    var search = toKeyValue(this.$$search),
14460        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
14461
14462    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
14463    // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
14464    this.$$absUrl = appBase + hashPrefix + this.$$url;
14465  };
14466
14467}
14468
14469
14470LocationHashbangInHtml5Url.prototype =
14471  LocationHashbangUrl.prototype =
14472  LocationHtml5Url.prototype = {
14473
14474  /**
14475   * Are we in html5 mode?
14476   * @private
14477   */
14478  $$html5: false,
14479
14480  /**
14481   * Has any change been replacing ?
14482   * @private
14483   */
14484  $$replace: false,
14485
14486  /**
14487   * @ngdoc method
14488   * @name $location#absUrl
14489   *
14490   * @description
14491   * This method is getter only.
14492   *
14493   * Return full url representation with all segments encoded according to rules specified in
14494   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
14495   *
14496   * @return {string} full url
14497   */
14498  absUrl: locationGetter('$$absUrl'),
14499
14500  /**
14501   * @ngdoc method
14502   * @name $location#url
14503   *
14504   * @description
14505   * This method is getter / setter.
14506   *
14507   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
14508   *
14509   * Change path, search and hash, when called with parameter and return `$location`.
14510   *
14511   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
14512   * @return {string} url
14513   */
14514  url: function(url) {
14515    if (isUndefined(url))
14516      return this.$$url;
14517
14518    var match = PATH_MATCH.exec(url);
14519    if (match[1]) this.path(decodeURIComponent(match[1]));
14520    if (match[2] || match[1]) this.search(match[3] || '');
14521    this.hash(match[5] || '');
14522
14523    return this;
14524  },
14525
14526  /**
14527   * @ngdoc method
14528   * @name $location#protocol
14529   *
14530   * @description
14531   * This method is getter only.
14532   *
14533   * Return protocol of current url.
14534   *
14535   * @return {string} protocol of current url
14536   */
14537  protocol: locationGetter('$$protocol'),
14538
14539  /**
14540   * @ngdoc method
14541   * @name $location#host
14542   *
14543   * @description
14544   * This method is getter only.
14545   *
14546   * Return host of current url.
14547   *
14548   * @return {string} host of current url.
14549   */
14550  host: locationGetter('$$host'),
14551
14552  /**
14553   * @ngdoc method
14554   * @name $location#port
14555   *
14556   * @description
14557   * This method is getter only.
14558   *
14559   * Return port of current url.
14560   *
14561   * @return {Number} port
14562   */
14563  port: locationGetter('$$port'),
14564
14565  /**
14566   * @ngdoc method
14567   * @name $location#path
14568   *
14569   * @description
14570   * This method is getter / setter.
14571   *
14572   * Return path of current url when called without any parameter.
14573   *
14574   * Change path when called with parameter and return `$location`.
14575   *
14576   * Note: Path should always begin with forward slash (/), this method will add the forward slash
14577   * if it is missing.
14578   *
14579   * @param {(string|number)=} path New path
14580   * @return {string} path
14581   */
14582  path: locationGetterSetter('$$path', function(path) {
14583    path = path ? path.toString() : '';
14584    return path.charAt(0) == '/' ? path : '/' + path;
14585  }),
14586
14587  /**
14588   * @ngdoc method
14589   * @name $location#search
14590   *
14591   * @description
14592   * This method is getter / setter.
14593   *
14594   * Return search part (as object) of current url when called without any parameter.
14595   *
14596   * Change search part when called with parameter and return `$location`.
14597   *
14598   *
14599   * ```js
14600   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
14601   * var searchObject = $location.search();
14602   * // => {foo: 'bar', baz: 'xoxo'}
14603   *
14604   *
14605   * // set foo to 'yipee'
14606   * $location.search('foo', 'yipee');
14607   * // => $location
14608   * ```
14609   *
14610   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
14611   * hash object.
14612   *
14613   * When called with a single argument the method acts as a setter, setting the `search` component
14614   * of `$location` to the specified value.
14615   *
14616   * If the argument is a hash object containing an array of values, these values will be encoded
14617   * as duplicate search parameters in the url.
14618   *
14619   * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
14620   * will override only a single search property.
14621   *
14622   * If `paramValue` is an array, it will override the property of the `search` component of
14623   * `$location` specified via the first argument.
14624   *
14625   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
14626   *
14627   * If `paramValue` is `true`, the property specified via the first argument will be added with no
14628   * value nor trailing equal sign.
14629   *
14630   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
14631   * one or more arguments returns `$location` object itself.
14632   */
14633  search: function(search, paramValue) {
14634    switch (arguments.length) {
14635      case 0:
14636        return this.$$search;
14637      case 1:
14638        if (isString(search) || isNumber(search)) {
14639          search = search.toString();
14640          this.$$search = parseKeyValue(search);
14641        } else if (isObject(search)) {
14642          // remove object undefined or null properties
14643          forEach(search, function(value, key) {
14644            if (value == null) delete search[key];
14645          });
14646
14647          this.$$search = search;
14648        } else {
14649          throw $locationMinErr('isrcharg',
14650              'The first argument of the `$location#search()` call must be a string or an object.');
14651        }
14652        break;
14653      default:
14654        if (isUndefined(paramValue) || paramValue === null) {
14655          delete this.$$search[search];
14656        } else {
14657          this.$$search[search] = paramValue;
14658        }
14659    }
14660
14661    this.$$compose();
14662    return this;
14663  },
14664
14665  /**
14666   * @ngdoc method
14667   * @name $location#hash
14668   *
14669   * @description
14670   * This method is getter / setter.
14671   *
14672   * Return hash fragment when called without any parameter.
14673   *
14674   * Change hash fragment when called with parameter and return `$location`.
14675   *
14676   * @param {(string|number)=} hash New hash fragment
14677   * @return {string} hash
14678   */
14679  hash: locationGetterSetter('$$hash', function(hash) {
14680    return hash ? hash.toString() : '';
14681  }),
14682
14683  /**
14684   * @ngdoc method
14685   * @name $location#replace
14686   *
14687   * @description
14688   * If called, all changes to $location during current `$digest` will be replacing current history
14689   * record, instead of adding new one.
14690   */
14691  replace: function() {
14692    this.$$replace = true;
14693    return this;
14694  }
14695};
14696
14697function locationGetter(property) {
14698  return function() {
14699    return this[property];
14700  };
14701}
14702
14703
14704function locationGetterSetter(property, preprocess) {
14705  return function(value) {
14706    if (isUndefined(value))
14707      return this[property];
14708
14709    this[property] = preprocess(value);
14710    this.$$compose();
14711
14712    return this;
14713  };
14714}
14715
14716
14717/**
14718 * @ngdoc service
14719 * @name $location
14720 *
14721 * @requires $rootElement
14722 *
14723 * @description
14724 * The $location service parses the URL in the browser address bar (based on the
14725 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
14726 * available to your application. Changes to the URL in the address bar are reflected into
14727 * $location service and changes to $location are reflected into the browser address bar.
14728 *
14729 * **The $location service:**
14730 *
14731 * - Exposes the current URL in the browser address bar, so you can
14732 *   - Watch and observe the URL.
14733 *   - Change the URL.
14734 * - Synchronizes the URL with the browser when the user
14735 *   - Changes the address bar.
14736 *   - Clicks the back or forward button (or clicks a History link).
14737 *   - Clicks on a link.
14738 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
14739 *
14740 * For more information see {@link guide/$location Developer Guide: Using $location}
14741 */
14742
14743/**
14744 * @ngdoc provider
14745 * @name $locationProvider
14746 * @description
14747 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
14748 */
14749function $LocationProvider(){
14750  var hashPrefix = '',
14751      html5Mode = false;
14752
14753  /**
14754   * @ngdoc method
14755   * @name $locationProvider#hashPrefix
14756   * @description
14757   * @param {string=} prefix Prefix for hash part (containing path and search)
14758   * @returns {*} current value if used as getter or itself (chaining) if used as setter
14759   */
14760  this.hashPrefix = function(prefix) {
14761    if (isDefined(prefix)) {
14762      hashPrefix = prefix;
14763      return this;
14764    } else {
14765      return hashPrefix;
14766    }
14767  };
14768
14769  /**
14770   * @ngdoc method
14771   * @name $locationProvider#html5Mode
14772   * @description
14773   * @param {boolean=} mode Use HTML5 strategy if available.
14774   * @returns {*} current value if used as getter or itself (chaining) if used as setter
14775   */
14776  this.html5Mode = function(mode) {
14777    if (isDefined(mode)) {
14778      html5Mode = mode;
14779      return this;
14780    } else {
14781      return html5Mode;
14782    }
14783  };
14784
14785  /**
14786   * @ngdoc event
14787   * @name $location#$locationChangeStart
14788   * @eventType broadcast on root scope
14789   * @description
14790   * Broadcasted before a URL will change. This change can be prevented by calling
14791   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
14792   * details about event object. Upon successful change
14793   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
14794   *
14795   * @param {Object} angularEvent Synthetic event object.
14796   * @param {string} newUrl New URL
14797   * @param {string=} oldUrl URL that was before it was changed.
14798   */
14799
14800  /**
14801   * @ngdoc event
14802   * @name $location#$locationChangeSuccess
14803   * @eventType broadcast on root scope
14804   * @description
14805   * Broadcasted after a URL was changed.
14806   *
14807   * @param {Object} angularEvent Synthetic event object.
14808   * @param {string} newUrl New URL
14809   * @param {string=} oldUrl URL that was before it was changed.
14810   */
14811
14812  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
14813      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
14814    var $location,
14815        LocationMode,
14816        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
14817        initialUrl = $browser.url(),
14818        appBase;
14819
14820    if (html5Mode) {
14821      appBase = serverBase(initialUrl) + (baseHref || '/');
14822      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
14823    } else {
14824      appBase = stripHash(initialUrl);
14825      LocationMode = LocationHashbangUrl;
14826    }
14827    $location = new LocationMode(appBase, '#' + hashPrefix);
14828    $location.$$parse($location.$$rewrite(initialUrl));
14829
14830    var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
14831
14832    $rootElement.on('click', function(event) {
14833      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
14834      // currently we open nice url link and redirect then
14835
14836      if (event.ctrlKey || event.metaKey || event.which == 2) return;
14837
14838      var elm = jqLite(event.target);
14839
14840      // traverse the DOM up to find first A tag
14841      while (lowercase(elm[0].nodeName) !== 'a') {
14842        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
14843        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
14844      }
14845
14846      var absHref = elm.prop('href');
14847
14848      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
14849        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
14850        // an animation.
14851        absHref = urlResolve(absHref.animVal).href;
14852      }
14853
14854      // Ignore when url is started with javascript: or mailto:
14855      if (IGNORE_URI_REGEXP.test(absHref)) return;
14856
14857      // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
14858      // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
14859      // somewhere#anchor or http://example.com/somewhere
14860      if (LocationMode === LocationHashbangInHtml5Url) {
14861        // get the actual href attribute - see
14862        // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
14863        var href = elm.attr('href') || elm.attr('xlink:href');
14864
14865        if (href && href.indexOf('://') < 0) {         // Ignore absolute URLs
14866          var prefix = '#' + hashPrefix;
14867          if (href[0] == '/') {
14868            // absolute path - replace old path
14869            absHref = appBase + prefix + href;
14870          } else if (href[0] == '#') {
14871            // local anchor
14872            absHref = appBase + prefix + ($location.path() || '/') + href;
14873          } else {
14874            // relative path - join with current path
14875            var stack = $location.path().split("/"),
14876              parts = href.split("/");
14877            if (stack.length === 2 && !stack[1]) stack.length = 1;
14878            for (var i=0; i<parts.length; i++) {
14879              if (parts[i] == ".")
14880                continue;
14881              else if (parts[i] == "..")
14882                stack.pop();
14883              else if (parts[i].length)
14884                stack.push(parts[i]);
14885            }
14886            absHref = appBase + prefix + stack.join('/');
14887          }
14888        }
14889      }
14890
14891      var rewrittenUrl = $location.$$rewrite(absHref);
14892
14893      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
14894        event.preventDefault();
14895        if (rewrittenUrl != $browser.url()) {
14896          // update location manually
14897          $location.$$parse(rewrittenUrl);
14898          $rootScope.$apply();
14899          // hack to work around FF6 bug 684208 when scenario runner clicks on links
14900          window.angular['ff-684208-preventDefault'] = true;
14901        }
14902      }
14903    });
14904
14905
14906    // rewrite hashbang url <> html5 url
14907    if ($location.absUrl() != initialUrl) {
14908      $browser.url($location.absUrl(), true);
14909    }
14910
14911    // update $location when $browser url changes
14912    $browser.onUrlChange(function(newUrl) {
14913      if ($location.absUrl() != newUrl) {
14914        $rootScope.$evalAsync(function() {
14915          var oldUrl = $location.absUrl();
14916
14917          $location.$$parse(newUrl);
14918          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
14919                                    oldUrl).defaultPrevented) {
14920            $location.$$parse(oldUrl);
14921            $browser.url(oldUrl);
14922          } else {
14923            afterLocationChange(oldUrl);
14924          }
14925        });
14926        if (!$rootScope.$$phase) $rootScope.$digest();
14927      }
14928    });
14929
14930    // update browser
14931    var changeCounter = 0;
14932    $rootScope.$watch(function $locationWatch() {
14933      var oldUrl = $browser.url();
14934      var currentReplace = $location.$$replace;
14935
14936      if (!changeCounter || oldUrl != $location.absUrl()) {
14937        changeCounter++;
14938        $rootScope.$evalAsync(function() {
14939          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
14940              defaultPrevented) {
14941            $location.$$parse(oldUrl);
14942          } else {
14943            $browser.url($location.absUrl(), currentReplace);
14944            afterLocationChange(oldUrl);
14945          }
14946        });
14947      }
14948      $location.$$replace = false;
14949
14950      return changeCounter;
14951    });
14952
14953    return $location;
14954
14955    function afterLocationChange(oldUrl) {
14956      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
14957    }
14958}];
14959}
14960
14961/**
14962 * @ngdoc service
14963 * @name $log
14964 * @requires $window
14965 *
14966 * @description
14967 * Simple service for logging. Default implementation safely writes the message
14968 * into the browser's console (if present).
14969 *
14970 * The main purpose of this service is to simplify debugging and troubleshooting.
14971 *
14972 * The default is to log `debug` messages. You can use
14973 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
14974 *
14975 * @example
14976   <example module="logExample">
14977     <file name="script.js">
14978       angular.module('logExample', [])
14979         .controller('LogController', ['$scope', '$log', function($scope, $log) {
14980           $scope.$log = $log;
14981           $scope.message = 'Hello World!';
14982         }]);
14983     </file>
14984     <file name="index.html">
14985       <div ng-controller="LogController">
14986         <p>Reload this page with open console, enter text and hit the log button...</p>
14987         Message:
14988         <input type="text" ng-model="message"/>
14989         <button ng-click="$log.log(message)">log</button>
14990         <button ng-click="$log.warn(message)">warn</button>
14991         <button ng-click="$log.info(message)">info</button>
14992         <button ng-click="$log.error(message)">error</button>
14993       </div>
14994     </file>
14995   </example>
14996 */
14997
14998/**
14999 * @ngdoc provider
15000 * @name $logProvider
15001 * @description
15002 * Use the `$logProvider` to configure how the application logs messages
15003 */
15004function $LogProvider(){
15005  var debug = true,
15006      self = this;
15007
15008  /**
15009   * @ngdoc method
15010   * @name $logProvider#debugEnabled
15011   * @description
15012   * @param {boolean=} flag enable or disable debug level messages
15013   * @returns {*} current value if used as getter or itself (chaining) if used as setter
15014   */
15015  this.debugEnabled = function(flag) {
15016    if (isDefined(flag)) {
15017      debug = flag;
15018    return this;
15019    } else {
15020      return debug;
15021    }
15022  };
15023
15024  this.$get = ['$window', function($window){
15025    return {
15026      /**
15027       * @ngdoc method
15028       * @name $log#log
15029       *
15030       * @description
15031       * Write a log message
15032       */
15033      log: consoleLog('log'),
15034
15035      /**
15036       * @ngdoc method
15037       * @name $log#info
15038       *
15039       * @description
15040       * Write an information message
15041       */
15042      info: consoleLog('info'),
15043
15044      /**
15045       * @ngdoc method
15046       * @name $log#warn
15047       *
15048       * @description
15049       * Write a warning message
15050       */
15051      warn: consoleLog('warn'),
15052
15053      /**
15054       * @ngdoc method
15055       * @name $log#error
15056       *
15057       * @description
15058       * Write an error message
15059       */
15060      error: consoleLog('error'),
15061
15062      /**
15063       * @ngdoc method
15064       * @name $log#debug
15065       *
15066       * @description
15067       * Write a debug message
15068       */
15069      debug: (function () {
15070        var fn = consoleLog('debug');
15071
15072        return function() {
15073          if (debug) {
15074            fn.apply(self, arguments);
15075          }
15076        };
15077      }())
15078    };
15079
15080    function formatError(arg) {
15081      if (arg instanceof Error) {
15082        if (arg.stack) {
15083          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
15084              ? 'Error: ' + arg.message + '\n' + arg.stack
15085              : arg.stack;
15086        } else if (arg.sourceURL) {
15087          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
15088        }
15089      }
15090      return arg;
15091    }
15092
15093    function consoleLog(type) {
15094      var console = $window.console || {},
15095          logFn = console[type] || console.log || noop,
15096          hasApply = false;
15097
15098      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
15099      // The reason behind this is that console.log has type "object" in IE8...
15100      try {
15101        hasApply = !!logFn.apply;
15102      } catch (e) {}
15103
15104      if (hasApply) {
15105        return function() {
15106          var args = [];
15107          forEach(arguments, function(arg) {
15108            args.push(formatError(arg));
15109          });
15110          return logFn.apply(console, args);
15111        };
15112      }
15113
15114      // we are IE which either doesn't have window.console => this is noop and we do nothing,
15115      // or we are IE where console.log doesn't have apply so we log at least first 2 args
15116      return function(arg1, arg2) {
15117        logFn(arg1, arg2 == null ? '' : arg2);
15118      };
15119    }
15120  }];
15121}
15122
15123var $parseMinErr = minErr('$parse');
15124var promiseWarningCache = {};
15125var promiseWarning;
15126
15127// Sandboxing Angular Expressions
15128// ------------------------------
15129// Angular expressions are generally considered safe because these expressions only have direct
15130// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
15131// obtaining a reference to native JS functions such as the Function constructor.
15132//
15133// As an example, consider the following Angular expression:
15134//
15135//   {}.toString.constructor('alert("evil JS code")')
15136//
15137// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
15138// against the expression language, but not to prevent exploits that were enabled by exposing
15139// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
15140// practice and therefore we are not even trying to protect against interaction with an object
15141// explicitly exposed in this way.
15142//
15143// In general, it is not possible to access a Window object from an angular expression unless a
15144// window or some DOM object that has a reference to window is published onto a Scope.
15145// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
15146// native objects.
15147
15148
15149function ensureSafeMemberName(name, fullExpression) {
15150  if (name === "__defineGetter__" || name === "__defineSetter__"
15151      || name === "__lookupGetter__" || name === "__lookupSetter__"
15152      || name === "__proto__") {
15153    throw $parseMinErr('isecfld',
15154        'Attempting to access a disallowed field in Angular expressions! '
15155        +'Expression: {0}', fullExpression);
15156  }
15157  return name;
15158}
15159
15160function ensureSafeObject(obj, fullExpression) {
15161  // nifty check if obj is Function that is fast and works across iframes and other contexts
15162  if (obj) {
15163    if (obj.constructor === obj) {
15164      throw $parseMinErr('isecfn',
15165          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
15166          fullExpression);
15167    } else if (// isWindow(obj)
15168        obj.document && obj.location && obj.alert && obj.setInterval) {
15169      throw $parseMinErr('isecwindow',
15170          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
15171          fullExpression);
15172    } else if (// isElement(obj)
15173        obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
15174      throw $parseMinErr('isecdom',
15175          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
15176          fullExpression);
15177    } else if (// block Object so that we can't get hold of dangerous Object.* methods
15178        obj === Object) {
15179      throw $parseMinErr('isecobj',
15180          'Referencing Object in Angular expressions is disallowed! Expression: {0}',
15181          fullExpression);
15182    }
15183  }
15184  return obj;
15185}
15186
15187var CALL = Function.prototype.call;
15188var APPLY = Function.prototype.apply;
15189var BIND = Function.prototype.bind;
15190
15191function ensureSafeFunction(obj, fullExpression) {
15192  if (obj) {
15193    if (obj.constructor === obj) {
15194      throw $parseMinErr('isecfn',
15195        'Referencing Function in Angular expressions is disallowed! Expression: {0}',
15196        fullExpression);
15197    } else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) {
15198      throw $parseMinErr('isecff',
15199        'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
15200        fullExpression);
15201    }
15202  }
15203}
15204
15205var OPERATORS = {
15206    /* jshint bitwise : false */
15207    'null':function(){return null;},
15208    'true':function(){return true;},
15209    'false':function(){return false;},
15210    undefined:noop,
15211    '+':function(self, locals, a,b){
15212      a=a(self, locals); b=b(self, locals);
15213      if (isDefined(a)) {
15214        if (isDefined(b)) {
15215          return a + b;
15216        }
15217        return a;
15218      }
15219      return isDefined(b)?b:undefined;},
15220    '-':function(self, locals, a,b){
15221          a=a(self, locals); b=b(self, locals);
15222          return (isDefined(a)?a:0)-(isDefined(b)?b:0);
15223        },
15224    '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
15225    '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
15226    '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
15227    '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
15228    '=':noop,
15229    '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
15230    '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
15231    '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
15232    '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
15233    '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
15234    '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
15235    '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
15236    '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
15237    '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
15238    '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
15239    '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
15240//    '|':function(self, locals, a,b){return a|b;},
15241    '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
15242    '!':function(self, locals, a){return !a(self, locals);}
15243};
15244/* jshint bitwise: true */
15245var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
15246
15247
15248/////////////////////////////////////////
15249
15250
15251/**
15252 * @constructor
15253 */
15254var Lexer = function (options) {
15255  this.options = options;
15256};
15257
15258Lexer.prototype = {
15259  constructor: Lexer,
15260
15261  lex: function (text) {
15262    this.text = text;
15263
15264    this.index = 0;
15265    this.ch = undefined;
15266    this.lastCh = ':'; // can start regexp
15267
15268    this.tokens = [];
15269
15270    while (this.index < this.text.length) {
15271      this.ch = this.text.charAt(this.index);
15272      if (this.is('"\'')) {
15273        this.readString(this.ch);
15274      } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
15275        this.readNumber();
15276      } else if (this.isIdent(this.ch)) {
15277        this.readIdent();
15278      } else if (this.is('(){}[].,;:?')) {
15279        this.tokens.push({
15280          index: this.index,
15281          text: this.ch
15282        });
15283        this.index++;
15284      } else if (this.isWhitespace(this.ch)) {
15285        this.index++;
15286        continue;
15287      } else {
15288        var ch2 = this.ch + this.peek();
15289        var ch3 = ch2 + this.peek(2);
15290        var fn = OPERATORS[this.ch];
15291        var fn2 = OPERATORS[ch2];
15292        var fn3 = OPERATORS[ch3];
15293        if (fn3) {
15294          this.tokens.push({index: this.index, text: ch3, fn: fn3});
15295          this.index += 3;
15296        } else if (fn2) {
15297          this.tokens.push({index: this.index, text: ch2, fn: fn2});
15298          this.index += 2;
15299        } else if (fn) {
15300          this.tokens.push({
15301            index: this.index,
15302            text: this.ch,
15303            fn: fn
15304          });
15305          this.index += 1;
15306        } else {
15307          this.throwError('Unexpected next character ', this.index, this.index + 1);
15308        }
15309      }
15310      this.lastCh = this.ch;
15311    }
15312    return this.tokens;
15313  },
15314
15315  is: function(chars) {
15316    return chars.indexOf(this.ch) !== -1;
15317  },
15318
15319  was: function(chars) {
15320    return chars.indexOf(this.lastCh) !== -1;
15321  },
15322
15323  peek: function(i) {
15324    var num = i || 1;
15325    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
15326  },
15327
15328  isNumber: function(ch) {
15329    return ('0' <= ch && ch <= '9');
15330  },
15331
15332  isWhitespace: function(ch) {
15333    // IE treats non-breaking space as \u00A0
15334    return (ch === ' ' || ch === '\r' || ch === '\t' ||
15335            ch === '\n' || ch === '\v' || ch === '\u00A0');
15336  },
15337
15338  isIdent: function(ch) {
15339    return ('a' <= ch && ch <= 'z' ||
15340            'A' <= ch && ch <= 'Z' ||
15341            '_' === ch || ch === '$');
15342  },
15343
15344  isExpOperator: function(ch) {
15345    return (ch === '-' || ch === '+' || this.isNumber(ch));
15346  },
15347
15348  throwError: function(error, start, end) {
15349    end = end || this.index;
15350    var colStr = (isDefined(start)
15351            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
15352            : ' ' + end);
15353    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
15354        error, colStr, this.text);
15355  },
15356
15357  readNumber: function() {
15358    var number = '';
15359    var start = this.index;
15360    while (this.index < this.text.length) {
15361      var ch = lowercase(this.text.charAt(this.index));
15362      if (ch == '.' || this.isNumber(ch)) {
15363        number += ch;
15364      } else {
15365        var peekCh = this.peek();
15366        if (ch == 'e' && this.isExpOperator(peekCh)) {
15367          number += ch;
15368        } else if (this.isExpOperator(ch) &&
15369            peekCh && this.isNumber(peekCh) &&
15370            number.charAt(number.length - 1) == 'e') {
15371          number += ch;
15372        } else if (this.isExpOperator(ch) &&
15373            (!peekCh || !this.isNumber(peekCh)) &&
15374            number.charAt(number.length - 1) == 'e') {
15375          this.throwError('Invalid exponent');
15376        } else {
15377          break;
15378        }
15379      }
15380      this.index++;
15381    }
15382    number = 1 * number;
15383    this.tokens.push({
15384      index: start,
15385      text: number,
15386      literal: true,
15387      constant: true,
15388      fn: function() { return number; }
15389    });
15390  },
15391
15392  readIdent: function() {
15393    var parser = this;
15394
15395    var ident = '';
15396    var start = this.index;
15397
15398    var lastDot, peekIndex, methodName, ch;
15399
15400    while (this.index < this.text.length) {
15401      ch = this.text.charAt(this.index);
15402      if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
15403        if (ch === '.') lastDot = this.index;
15404        ident += ch;
15405      } else {
15406        break;
15407      }
15408      this.index++;
15409    }
15410
15411    //check if this is not a method invocation and if it is back out to last dot
15412    if (lastDot) {
15413      peekIndex = this.index;
15414      while (peekIndex < this.text.length) {
15415        ch = this.text.charAt(peekIndex);
15416        if (ch === '(') {
15417          methodName = ident.substr(lastDot - start + 1);
15418          ident = ident.substr(0, lastDot - start);
15419          this.index = peekIndex;
15420          break;
15421        }
15422        if (this.isWhitespace(ch)) {
15423          peekIndex++;
15424        } else {
15425          break;
15426        }
15427      }
15428    }
15429
15430
15431    var token = {
15432      index: start,
15433      text: ident
15434    };
15435
15436    // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
15437    if (OPERATORS.hasOwnProperty(ident)) {
15438      token.fn = OPERATORS[ident];
15439      token.literal = true;
15440      token.constant = true;
15441    } else {
15442      var getter = getterFn(ident, this.options, this.text);
15443      token.fn = extend(function(self, locals) {
15444        return (getter(self, locals));
15445      }, {
15446        assign: function(self, value) {
15447          return setter(self, ident, value, parser.text, parser.options);
15448        }
15449      });
15450    }
15451
15452    this.tokens.push(token);
15453
15454    if (methodName) {
15455      this.tokens.push({
15456        index:lastDot,
15457        text: '.'
15458      });
15459      this.tokens.push({
15460        index: lastDot + 1,
15461        text: methodName
15462      });
15463    }
15464  },
15465
15466  readString: function(quote) {
15467    var start = this.index;
15468    this.index++;
15469    var string = '';
15470    var rawString = quote;
15471    var escape = false;
15472    while (this.index < this.text.length) {
15473      var ch = this.text.charAt(this.index);
15474      rawString += ch;
15475      if (escape) {
15476        if (ch === 'u') {
15477          var hex = this.text.substring(this.index + 1, this.index + 5);
15478          if (!hex.match(/[\da-f]{4}/i))
15479            this.throwError('Invalid unicode escape [\\u' + hex + ']');
15480          this.index += 4;
15481          string += String.fromCharCode(parseInt(hex, 16));
15482        } else {
15483          var rep = ESCAPE[ch];
15484          string = string + (rep || ch);
15485        }
15486        escape = false;
15487      } else if (ch === '\\') {
15488        escape = true;
15489      } else if (ch === quote) {
15490        this.index++;
15491        this.tokens.push({
15492          index: start,
15493          text: rawString,
15494          string: string,
15495          literal: true,
15496          constant: true,
15497          fn: function() { return string; }
15498        });
15499        return;
15500      } else {
15501        string += ch;
15502      }
15503      this.index++;
15504    }
15505    this.throwError('Unterminated quote', start);
15506  }
15507};
15508
15509
15510/**
15511 * @constructor
15512 */
15513var Parser = function (lexer, $filter, options) {
15514  this.lexer = lexer;
15515  this.$filter = $filter;
15516  this.options = options;
15517};
15518
15519Parser.ZERO = extend(function () {
15520  return 0;
15521}, {
15522  constant: true
15523});
15524
15525Parser.prototype = {
15526  constructor: Parser,
15527
15528  parse: function (text) {
15529    this.text = text;
15530
15531    this.tokens = this.lexer.lex(text);
15532
15533    var value = this.statements();
15534
15535    if (this.tokens.length !== 0) {
15536      this.throwError('is an unexpected token', this.tokens[0]);
15537    }
15538
15539    value.literal = !!value.literal;
15540    value.constant = !!value.constant;
15541
15542    return value;
15543  },
15544
15545  primary: function () {
15546    var primary;
15547    if (this.expect('(')) {
15548      primary = this.filterChain();
15549      this.consume(')');
15550    } else if (this.expect('[')) {
15551      primary = this.arrayDeclaration();
15552    } else if (this.expect('{')) {
15553      primary = this.object();
15554    } else {
15555      var token = this.expect();
15556      primary = token.fn;
15557      if (!primary) {
15558        this.throwError('not a primary expression', token);
15559      }
15560      primary.literal = !!token.literal;
15561      primary.constant = !!token.constant;
15562    }
15563
15564    var next, context;
15565    while ((next = this.expect('(', '[', '.'))) {
15566      if (next.text === '(') {
15567        primary = this.functionCall(primary, context);
15568        context = null;
15569      } else if (next.text === '[') {
15570        context = primary;
15571        primary = this.objectIndex(primary);
15572      } else if (next.text === '.') {
15573        context = primary;
15574        primary = this.fieldAccess(primary);
15575      } else {
15576        this.throwError('IMPOSSIBLE');
15577      }
15578    }
15579    return primary;
15580  },
15581
15582  throwError: function(msg, token) {
15583    throw $parseMinErr('syntax',
15584        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
15585          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
15586  },
15587
15588  peekToken: function() {
15589    if (this.tokens.length === 0)
15590      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
15591    return this.tokens[0];
15592  },
15593
15594  peek: function(e1, e2, e3, e4) {
15595    if (this.tokens.length > 0) {
15596      var token = this.tokens[0];
15597      var t = token.text;
15598      if (t === e1 || t === e2 || t === e3 || t === e4 ||
15599          (!e1 && !e2 && !e3 && !e4)) {
15600        return token;
15601      }
15602    }
15603    return false;
15604  },
15605
15606  expect: function(e1, e2, e3, e4){
15607    var token = this.peek(e1, e2, e3, e4);
15608    if (token) {
15609      this.tokens.shift();
15610      return token;
15611    }
15612    return false;
15613  },
15614
15615  consume: function(e1){
15616    if (!this.expect(e1)) {
15617      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
15618    }
15619  },
15620
15621  unaryFn: function(fn, right) {
15622    return extend(function(self, locals) {
15623      return fn(self, locals, right);
15624    }, {
15625      constant:right.constant
15626    });
15627  },
15628
15629  ternaryFn: function(left, middle, right){
15630    return extend(function(self, locals){
15631      return left(self, locals) ? middle(self, locals) : right(self, locals);
15632    }, {
15633      constant: left.constant && middle.constant && right.constant
15634    });
15635  },
15636
15637  binaryFn: function(left, fn, right) {
15638    return extend(function(self, locals) {
15639      return fn(self, locals, left, right);
15640    }, {
15641      constant:left.constant && right.constant
15642    });
15643  },
15644
15645  statements: function() {
15646    var statements = [];
15647    while (true) {
15648      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
15649        statements.push(this.filterChain());
15650      if (!this.expect(';')) {
15651        // optimize for the common case where there is only one statement.
15652        // TODO(size): maybe we should not support multiple statements?
15653        return (statements.length === 1)
15654            ? statements[0]
15655            : function(self, locals) {
15656                var value;
15657                for (var i = 0; i < statements.length; i++) {
15658                  var statement = statements[i];
15659                  if (statement) {
15660                    value = statement(self, locals);
15661                  }
15662                }
15663                return value;
15664              };
15665      }
15666    }
15667  },
15668
15669  filterChain: function() {
15670    var left = this.expression();
15671    var token;
15672    while (true) {
15673      if ((token = this.expect('|'))) {
15674        left = this.binaryFn(left, token.fn, this.filter());
15675      } else {
15676        return left;
15677      }
15678    }
15679  },
15680
15681  filter: function() {
15682    var token = this.expect();
15683    var fn = this.$filter(token.text);
15684    var argsFn = [];
15685    while (true) {
15686      if ((token = this.expect(':'))) {
15687        argsFn.push(this.expression());
15688      } else {
15689        var fnInvoke = function(self, locals, input) {
15690          var args = [input];
15691          for (var i = 0; i < argsFn.length; i++) {
15692            args.push(argsFn[i](self, locals));
15693          }
15694          return fn.apply(self, args);
15695        };
15696        return function() {
15697          return fnInvoke;
15698        };
15699      }
15700    }
15701  },
15702
15703  expression: function() {
15704    return this.assignment();
15705  },
15706
15707  assignment: function() {
15708    var left = this.ternary();
15709    var right;
15710    var token;
15711    if ((token = this.expect('='))) {
15712      if (!left.assign) {
15713        this.throwError('implies assignment but [' +
15714            this.text.substring(0, token.index) + '] can not be assigned to', token);
15715      }
15716      right = this.ternary();
15717      return function(scope, locals) {
15718        return left.assign(scope, right(scope, locals), locals);
15719      };
15720    }
15721    return left;
15722  },
15723
15724  ternary: function() {
15725    var left = this.logicalOR();
15726    var middle;
15727    var token;
15728    if ((token = this.expect('?'))) {
15729      middle = this.assignment();
15730      if ((token = this.expect(':'))) {
15731        return this.ternaryFn(left, middle, this.assignment());
15732      } else {
15733        this.throwError('expected :', token);
15734      }
15735    } else {
15736      return left;
15737    }
15738  },
15739
15740  logicalOR: function() {
15741    var left = this.logicalAND();
15742    var token;
15743    while (true) {
15744      if ((token = this.expect('||'))) {
15745        left = this.binaryFn(left, token.fn, this.logicalAND());
15746      } else {
15747        return left;
15748      }
15749    }
15750  },
15751
15752  logicalAND: function() {
15753    var left = this.equality();
15754    var token;
15755    if ((token = this.expect('&&'))) {
15756      left = this.binaryFn(left, token.fn, this.logicalAND());
15757    }
15758    return left;
15759  },
15760
15761  equality: function() {
15762    var left = this.relational();
15763    var token;
15764    if ((token = this.expect('==','!=','===','!=='))) {
15765      left = this.binaryFn(left, token.fn, this.equality());
15766    }
15767    return left;
15768  },
15769
15770  relational: function() {
15771    var left = this.additive();
15772    var token;
15773    if ((token = this.expect('<', '>', '<=', '>='))) {
15774      left = this.binaryFn(left, token.fn, this.relational());
15775    }
15776    return left;
15777  },
15778
15779  additive: function() {
15780    var left = this.multiplicative();
15781    var token;
15782    while ((token = this.expect('+','-'))) {
15783      left = this.binaryFn(left, token.fn, this.multiplicative());
15784    }
15785    return left;
15786  },
15787
15788  multiplicative: function() {
15789    var left = this.unary();
15790    var token;
15791    while ((token = this.expect('*','/','%'))) {
15792      left = this.binaryFn(left, token.fn, this.unary());
15793    }
15794    return left;
15795  },
15796
15797  unary: function() {
15798    var token;
15799    if (this.expect('+')) {
15800      return this.primary();
15801    } else if ((token = this.expect('-'))) {
15802      return this.binaryFn(Parser.ZERO, token.fn, this.unary());
15803    } else if ((token = this.expect('!'))) {
15804      return this.unaryFn(token.fn, this.unary());
15805    } else {
15806      return this.primary();
15807    }
15808  },
15809
15810  fieldAccess: function(object) {
15811    var parser = this;
15812    var field = this.expect().text;
15813    var getter = getterFn(field, this.options, this.text);
15814
15815    return extend(function(scope, locals, self) {
15816      return getter(self || object(scope, locals));
15817    }, {
15818      assign: function(scope, value, locals) {
15819        var o = object(scope, locals);
15820        if (!o) object.assign(scope, o = {});
15821        return setter(o, field, value, parser.text, parser.options);
15822      }
15823    });
15824  },
15825
15826  objectIndex: function(obj) {
15827    var parser = this;
15828
15829    var indexFn = this.expression();
15830    this.consume(']');
15831
15832    return extend(function(self, locals) {
15833      var o = obj(self, locals),
15834          i = indexFn(self, locals),
15835          v, p;
15836
15837      ensureSafeMemberName(i, parser.text);
15838      if (!o) return undefined;
15839      v = ensureSafeObject(o[i], parser.text);
15840      if (v && v.then && parser.options.unwrapPromises) {
15841        p = v;
15842        if (!('$$v' in v)) {
15843          p.$$v = undefined;
15844          p.then(function(val) { p.$$v = val; });
15845        }
15846        v = v.$$v;
15847      }
15848      return v;
15849    }, {
15850      assign: function(self, value, locals) {
15851        var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
15852        // prevent overwriting of Function.constructor which would break ensureSafeObject check
15853        var o = ensureSafeObject(obj(self, locals), parser.text);
15854        if (!o) obj.assign(self, o = {});
15855        return o[key] = value;
15856      }
15857    });
15858  },
15859
15860  functionCall: function(fn, contextGetter) {
15861    var argsFn = [];
15862    if (this.peekToken().text !== ')') {
15863      do {
15864        argsFn.push(this.expression());
15865      } while (this.expect(','));
15866    }
15867    this.consume(')');
15868
15869    var parser = this;
15870
15871    return function(scope, locals) {
15872      var args = [];
15873      var context = contextGetter ? contextGetter(scope, locals) : scope;
15874
15875      for (var i = 0; i < argsFn.length; i++) {
15876        args.push(ensureSafeObject(argsFn[i](scope, locals), parser.text));
15877      }
15878      var fnPtr = fn(scope, locals, context) || noop;
15879
15880      ensureSafeObject(context, parser.text);
15881      ensureSafeFunction(fnPtr, parser.text);
15882
15883      // IE stupidity! (IE doesn't have apply for some native functions)
15884      var v = fnPtr.apply
15885            ? fnPtr.apply(context, args)
15886            : fnPtr(args[0], args[1], args[2], args[3], args[4]);
15887
15888      return ensureSafeObject(v, parser.text);
15889    };
15890  },
15891
15892  // This is used with json array declaration
15893  arrayDeclaration: function () {
15894    var elementFns = [];
15895    var allConstant = true;
15896    if (this.peekToken().text !== ']') {
15897      do {
15898        if (this.peek(']')) {
15899          // Support trailing commas per ES5.1.
15900          break;
15901        }
15902        var elementFn = this.expression();
15903        elementFns.push(elementFn);
15904        if (!elementFn.constant) {
15905          allConstant = false;
15906        }
15907      } while (this.expect(','));
15908    }
15909    this.consume(']');
15910
15911    return extend(function(self, locals) {
15912      var array = [];
15913      for (var i = 0; i < elementFns.length; i++) {
15914        array.push(elementFns[i](self, locals));
15915      }
15916      return array;
15917    }, {
15918      literal: true,
15919      constant: allConstant
15920    });
15921  },
15922
15923  object: function () {
15924    var keyValues = [];
15925    var allConstant = true;
15926    if (this.peekToken().text !== '}') {
15927      do {
15928        if (this.peek('}')) {
15929          // Support trailing commas per ES5.1.
15930          break;
15931        }
15932        var token = this.expect(),
15933        key = token.string || token.text;
15934        this.consume(':');
15935        var value = this.expression();
15936        keyValues.push({key: key, value: value});
15937        if (!value.constant) {
15938          allConstant = false;
15939        }
15940      } while (this.expect(','));
15941    }
15942    this.consume('}');
15943
15944    return extend(function(self, locals) {
15945      var object = {};
15946      for (var i = 0; i < keyValues.length; i++) {
15947        var keyValue = keyValues[i];
15948        object[keyValue.key] = keyValue.value(self, locals);
15949      }
15950      return object;
15951    }, {
15952      literal: true,
15953      constant: allConstant
15954    });
15955  }
15956};
15957
15958
15959//////////////////////////////////////////////////
15960// Parser helper functions
15961//////////////////////////////////////////////////
15962
15963function setter(obj, path, setValue, fullExp, options) {
15964  ensureSafeObject(obj, fullExp);
15965
15966  //needed?
15967  options = options || {};
15968
15969  var element = path.split('.'), key;
15970  for (var i = 0; element.length > 1; i++) {
15971    key = ensureSafeMemberName(element.shift(), fullExp);
15972    var propertyObj = ensureSafeObject(obj[key], fullExp);
15973    if (!propertyObj) {
15974      propertyObj = {};
15975      obj[key] = propertyObj;
15976    }
15977    obj = propertyObj;
15978    if (obj.then && options.unwrapPromises) {
15979      promiseWarning(fullExp);
15980      if (!("$$v" in obj)) {
15981        (function(promise) {
15982          promise.then(function(val) { promise.$$v = val; }); }
15983        )(obj);
15984      }
15985      if (obj.$$v === undefined) {
15986        obj.$$v = {};
15987      }
15988      obj = obj.$$v;
15989    }
15990  }
15991  key = ensureSafeMemberName(element.shift(), fullExp);
15992  ensureSafeObject(obj[key], fullExp);
15993  obj[key] = setValue;
15994  return setValue;
15995}
15996
15997var getterFnCache = {};
15998
15999/**
16000 * Implementation of the "Black Hole" variant from:
16001 * - http://jsperf.com/angularjs-parse-getter/4
16002 * - http://jsperf.com/path-evaluation-simplified/7
16003 */
16004function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
16005  ensureSafeMemberName(key0, fullExp);
16006  ensureSafeMemberName(key1, fullExp);
16007  ensureSafeMemberName(key2, fullExp);
16008  ensureSafeMemberName(key3, fullExp);
16009  ensureSafeMemberName(key4, fullExp);
16010
16011  return !options.unwrapPromises
16012      ? function cspSafeGetter(scope, locals) {
16013          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
16014
16015          if (pathVal == null) return pathVal;
16016          pathVal = pathVal[key0];
16017
16018          if (!key1) return pathVal;
16019          if (pathVal == null) return undefined;
16020          pathVal = pathVal[key1];
16021
16022          if (!key2) return pathVal;
16023          if (pathVal == null) return undefined;
16024          pathVal = pathVal[key2];
16025
16026          if (!key3) return pathVal;
16027          if (pathVal == null) return undefined;
16028          pathVal = pathVal[key3];
16029
16030          if (!key4) return pathVal;
16031          if (pathVal == null) return undefined;
16032          pathVal = pathVal[key4];
16033
16034          return pathVal;
16035        }
16036      : function cspSafePromiseEnabledGetter(scope, locals) {
16037          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
16038              promise;
16039
16040          if (pathVal == null) return pathVal;
16041
16042          pathVal = pathVal[key0];
16043          if (pathVal && pathVal.then) {
16044            promiseWarning(fullExp);
16045            if (!("$$v" in pathVal)) {
16046              promise = pathVal;
16047              promise.$$v = undefined;
16048              promise.then(function(val) { promise.$$v = val; });
16049            }
16050            pathVal = pathVal.$$v;
16051          }
16052
16053          if (!key1) return pathVal;
16054          if (pathVal == null) return undefined;
16055          pathVal = pathVal[key1];
16056          if (pathVal && pathVal.then) {
16057            promiseWarning(fullExp);
16058            if (!("$$v" in pathVal)) {
16059              promise = pathVal;
16060              promise.$$v = undefined;
16061              promise.then(function(val) { promise.$$v = val; });
16062            }
16063            pathVal = pathVal.$$v;
16064          }
16065
16066          if (!key2) return pathVal;
16067          if (pathVal == null) return undefined;
16068          pathVal = pathVal[key2];
16069          if (pathVal && pathVal.then) {
16070            promiseWarning(fullExp);
16071            if (!("$$v" in pathVal)) {
16072              promise = pathVal;
16073              promise.$$v = undefined;
16074              promise.then(function(val) { promise.$$v = val; });
16075            }
16076            pathVal = pathVal.$$v;
16077          }
16078
16079          if (!key3) return pathVal;
16080          if (pathVal == null) return undefined;
16081          pathVal = pathVal[key3];
16082          if (pathVal && pathVal.then) {
16083            promiseWarning(fullExp);
16084            if (!("$$v" in pathVal)) {
16085              promise = pathVal;
16086              promise.$$v = undefined;
16087              promise.then(function(val) { promise.$$v = val; });
16088            }
16089            pathVal = pathVal.$$v;
16090          }
16091
16092          if (!key4) return pathVal;
16093          if (pathVal == null) return undefined;
16094          pathVal = pathVal[key4];
16095          if (pathVal && pathVal.then) {
16096            promiseWarning(fullExp);
16097            if (!("$$v" in pathVal)) {
16098              promise = pathVal;
16099              promise.$$v = undefined;
16100              promise.then(function(val) { promise.$$v = val; });
16101            }
16102            pathVal = pathVal.$$v;
16103          }
16104          return pathVal;
16105        };
16106}
16107
16108function getterFn(path, options, fullExp) {
16109  // Check whether the cache has this getter already.
16110  // We can use hasOwnProperty directly on the cache because we ensure,
16111  // see below, that the cache never stores a path called 'hasOwnProperty'
16112  if (getterFnCache.hasOwnProperty(path)) {
16113    return getterFnCache[path];
16114  }
16115
16116  var pathKeys = path.split('.'),
16117      pathKeysLength = pathKeys.length,
16118      fn;
16119
16120  // http://jsperf.com/angularjs-parse-getter/6
16121  if (options.csp) {
16122    if (pathKeysLength < 6) {
16123      fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
16124                          options);
16125    } else {
16126      fn = function(scope, locals) {
16127        var i = 0, val;
16128        do {
16129          val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
16130                                pathKeys[i++], fullExp, options)(scope, locals);
16131
16132          locals = undefined; // clear after first iteration
16133          scope = val;
16134        } while (i < pathKeysLength);
16135        return val;
16136      };
16137    }
16138  } else {
16139    var code = 'var p;\n';
16140    forEach(pathKeys, function(key, index) {
16141      ensureSafeMemberName(key, fullExp);
16142      code += 'if(s == null) return undefined;\n' +
16143              's='+ (index
16144                      // we simply dereference 's' on any .dot notation
16145                      ? 's'
16146                      // but if we are first then we check locals first, and if so read it first
16147                      : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
16148              (options.unwrapPromises
16149                ? 'if (s && s.then) {\n' +
16150                  ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
16151                  ' if (!("$$v" in s)) {\n' +
16152                    ' p=s;\n' +
16153                    ' p.$$v = undefined;\n' +
16154                    ' p.then(function(v) {p.$$v=v;});\n' +
16155                    '}\n' +
16156                  ' s=s.$$v\n' +
16157                '}\n'
16158                : '');
16159    });
16160    code += 'return s;';
16161
16162    /* jshint -W054 */
16163    var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
16164    /* jshint +W054 */
16165    evaledFnGetter.toString = valueFn(code);
16166    fn = options.unwrapPromises ? function(scope, locals) {
16167      return evaledFnGetter(scope, locals, promiseWarning);
16168    } : evaledFnGetter;
16169  }
16170
16171  // Only cache the value if it's not going to mess up the cache object
16172  // This is more performant that using Object.prototype.hasOwnProperty.call
16173  if (path !== 'hasOwnProperty') {
16174    getterFnCache[path] = fn;
16175  }
16176  return fn;
16177}
16178
16179///////////////////////////////////
16180
16181/**
16182 * @ngdoc service
16183 * @name $parse
16184 * @kind function
16185 *
16186 * @description
16187 *
16188 * Converts Angular {@link guide/expression expression} into a function.
16189 *
16190 * ```js
16191 *   var getter = $parse('user.name');
16192 *   var setter = getter.assign;
16193 *   var context = {user:{name:'angular'}};
16194 *   var locals = {user:{name:'local'}};
16195 *
16196 *   expect(getter(context)).toEqual('angular');
16197 *   setter(context, 'newValue');
16198 *   expect(context.user.name).toEqual('newValue');
16199 *   expect(getter(context, locals)).toEqual('local');
16200 * ```
16201 *
16202 *
16203 * @param {string} expression String expression to compile.
16204 * @returns {function(context, locals)} a function which represents the compiled expression:
16205 *
16206 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
16207 *      are evaluated against (typically a scope object).
16208 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
16209 *      `context`.
16210 *
16211 *    The returned function also has the following properties:
16212 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
16213 *        literal.
16214 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
16215 *        constant literals.
16216 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
16217 *        set to a function to change its value on the given context.
16218 *
16219 */
16220
16221
16222/**
16223 * @ngdoc provider
16224 * @name $parseProvider
16225 * @kind function
16226 *
16227 * @description
16228 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
16229 *  service.
16230 */
16231function $ParseProvider() {
16232  var cache = {};
16233
16234  var $parseOptions = {
16235    csp: false,
16236    unwrapPromises: false,
16237    logPromiseWarnings: true
16238  };
16239
16240
16241  /**
16242   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
16243   *
16244   * @ngdoc method
16245   * @name $parseProvider#unwrapPromises
16246   * @description
16247   *
16248   * **This feature is deprecated, see deprecation notes below for more info**
16249   *
16250   * If set to true (default is false), $parse will unwrap promises automatically when a promise is
16251   * found at any part of the expression. In other words, if set to true, the expression will always
16252   * result in a non-promise value.
16253   *
16254   * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
16255   * the fulfillment value is used in place of the promise while evaluating the expression.
16256   *
16257   * **Deprecation notice**
16258   *
16259   * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
16260   * dichotomy between data access in templates (accessed as raw values) and controller code
16261   * (accessed as promises).
16262   *
16263   * In most code we ended up resolving promises manually in controllers anyway and thus unifying
16264   * the model access there.
16265   *
16266   * Other downsides of automatic promise unwrapping:
16267   *
16268   * - when building components it's often desirable to receive the raw promises
16269   * - adds complexity and slows down expression evaluation
16270   * - makes expression code pre-generation unattractive due to the amount of code that needs to be
16271   *   generated
16272   * - makes IDE auto-completion and tool support hard
16273   *
16274   * **Warning Logs**
16275   *
16276   * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
16277   * promise (to reduce the noise, each expression is logged only once). To disable this logging use
16278   * `$parseProvider.logPromiseWarnings(false)` api.
16279   *
16280   *
16281   * @param {boolean=} value New value.
16282   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
16283   *                         setter.
16284   */
16285  this.unwrapPromises = function(value) {
16286    if (isDefined(value)) {
16287      $parseOptions.unwrapPromises = !!value;
16288      return this;
16289    } else {
16290      return $parseOptions.unwrapPromises;
16291    }
16292  };
16293
16294
16295  /**
16296   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
16297   *
16298   * @ngdoc method
16299   * @name $parseProvider#logPromiseWarnings
16300   * @description
16301   *
16302   * Controls whether Angular should log a warning on any encounter of a promise in an expression.
16303   *
16304   * The default is set to `true`.
16305   *
16306   * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
16307   *
16308   * @param {boolean=} value New value.
16309   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
16310   *                         setter.
16311   */
16312 this.logPromiseWarnings = function(value) {
16313    if (isDefined(value)) {
16314      $parseOptions.logPromiseWarnings = value;
16315      return this;
16316    } else {
16317      return $parseOptions.logPromiseWarnings;
16318    }
16319  };
16320
16321
16322  this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
16323    $parseOptions.csp = $sniffer.csp;
16324
16325    promiseWarning = function promiseWarningFn(fullExp) {
16326      if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
16327      promiseWarningCache[fullExp] = true;
16328      $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
16329          'Automatic unwrapping of promises in Angular expressions is deprecated.');
16330    };
16331
16332    return function(exp) {
16333      var parsedExpression;
16334
16335      switch (typeof exp) {
16336        case 'string':
16337
16338          if (cache.hasOwnProperty(exp)) {
16339            return cache[exp];
16340          }
16341
16342          var lexer = new Lexer($parseOptions);
16343          var parser = new Parser(lexer, $filter, $parseOptions);
16344          parsedExpression = parser.parse(exp);
16345
16346          if (exp !== 'hasOwnProperty') {
16347            // Only cache the value if it's not going to mess up the cache object
16348            // This is more performant that using Object.prototype.hasOwnProperty.call
16349            cache[exp] = parsedExpression;
16350          }
16351
16352          return parsedExpression;
16353
16354        case 'function':
16355          return exp;
16356
16357        default:
16358          return noop;
16359      }
16360    };
16361  }];
16362}
16363
16364/**
16365 * @ngdoc service
16366 * @name $q
16367 * @requires $rootScope
16368 *
16369 * @description
16370 * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
16371 *
16372 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
16373 * interface for interacting with an object that represents the result of an action that is
16374 * performed asynchronously, and may or may not be finished at any given point in time.
16375 *
16376 * From the perspective of dealing with error handling, deferred and promise APIs are to
16377 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
16378 *
16379 * ```js
16380 *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
16381 *   // are available in the current lexical scope (they could have been injected or passed in).
16382 *
16383 *   function asyncGreet(name) {
16384 *     var deferred = $q.defer();
16385 *
16386 *     setTimeout(function() {
16387 *       deferred.notify('About to greet ' + name + '.');
16388 *
16389 *       if (okToGreet(name)) {
16390 *         deferred.resolve('Hello, ' + name + '!');
16391 *       } else {
16392 *         deferred.reject('Greeting ' + name + ' is not allowed.');
16393 *       }
16394 *     }, 1000);
16395 *
16396 *     return deferred.promise;
16397 *   }
16398 *
16399 *   var promise = asyncGreet('Robin Hood');
16400 *   promise.then(function(greeting) {
16401 *     alert('Success: ' + greeting);
16402 *   }, function(reason) {
16403 *     alert('Failed: ' + reason);
16404 *   }, function(update) {
16405 *     alert('Got notification: ' + update);
16406 *   });
16407 * ```
16408 *
16409 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
16410 * comes in the way of guarantees that promise and deferred APIs make, see
16411 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
16412 *
16413 * Additionally the promise api allows for composition that is very hard to do with the
16414 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
16415 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
16416 * section on serial or parallel joining of promises.
16417 *
16418 *
16419 * # The Deferred API
16420 *
16421 * A new instance of deferred is constructed by calling `$q.defer()`.
16422 *
16423 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
16424 * that can be used for signaling the successful or unsuccessful completion, as well as the status
16425 * of the task.
16426 *
16427 * **Methods**
16428 *
16429 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
16430 *   constructed via `$q.reject`, the promise will be rejected instead.
16431 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
16432 *   resolving it with a rejection constructed via `$q.reject`.
16433 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
16434 *   multiple times before the promise is either resolved or rejected.
16435 *
16436 * **Properties**
16437 *
16438 * - promise – `{Promise}` – promise object associated with this deferred.
16439 *
16440 *
16441 * # The Promise API
16442 *
16443 * A new promise instance is created when a deferred instance is created and can be retrieved by
16444 * calling `deferred.promise`.
16445 *
16446 * The purpose of the promise object is to allow for interested parties to get access to the result
16447 * of the deferred task when it completes.
16448 *
16449 * **Methods**
16450 *
16451 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
16452 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
16453 *   as soon as the result is available. The callbacks are called with a single argument: the result
16454 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
16455 *   provide a progress indication, before the promise is resolved or rejected.
16456 *
16457 *   This method *returns a new promise* which is resolved or rejected via the return value of the
16458 *   `successCallback`, `errorCallback`. It also notifies via the return value of the
16459 *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
16460 *   method.
16461 *
16462 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
16463 *
16464 * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
16465 *   but to do so without modifying the final value. This is useful to release resources or do some
16466 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
16467 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
16468 *   more information.
16469 *
16470 *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
16471 *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
16472 *   make your code IE8 and Android 2.x compatible.
16473 *
16474 * # Chaining promises
16475 *
16476 * Because calling the `then` method of a promise returns a new derived promise, it is easily
16477 * possible to create a chain of promises:
16478 *
16479 * ```js
16480 *   promiseB = promiseA.then(function(result) {
16481 *     return result + 1;
16482 *   });
16483 *
16484 *   // promiseB will be resolved immediately after promiseA is resolved and its value
16485 *   // will be the result of promiseA incremented by 1
16486 * ```
16487 *
16488 * It is possible to create chains of any length and since a promise can be resolved with another
16489 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
16490 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
16491 * $http's response interceptors.
16492 *
16493 *
16494 * # Differences between Kris Kowal's Q and $q
16495 *
16496 *  There are two main differences:
16497 *
16498 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
16499 *   mechanism in angular, which means faster propagation of resolution or rejection into your
16500 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
16501 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
16502 *   all the important functionality needed for common async tasks.
16503 *
16504 *  # Testing
16505 *
16506 *  ```js
16507 *    it('should simulate promise', inject(function($q, $rootScope) {
16508 *      var deferred = $q.defer();
16509 *      var promise = deferred.promise;
16510 *      var resolvedValue;
16511 *
16512 *      promise.then(function(value) { resolvedValue = value; });
16513 *      expect(resolvedValue).toBeUndefined();
16514 *
16515 *      // Simulate resolving of promise
16516 *      deferred.resolve(123);
16517 *      // Note that the 'then' function does not get called synchronously.
16518 *      // This is because we want the promise API to always be async, whether or not
16519 *      // it got called synchronously or asynchronously.
16520 *      expect(resolvedValue).toBeUndefined();
16521 *
16522 *      // Propagate promise resolution to 'then' functions using $apply().
16523 *      $rootScope.$apply();
16524 *      expect(resolvedValue).toEqual(123);
16525 *    }));
16526 *  ```
16527 */
16528function $QProvider() {
16529
16530  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
16531    return qFactory(function(callback) {
16532      $rootScope.$evalAsync(callback);
16533    }, $exceptionHandler);
16534  }];
16535}
16536
16537
16538/**
16539 * Constructs a promise manager.
16540 *
16541 * @param {function(Function)} nextTick Function for executing functions in the next turn.
16542 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
16543 *     debugging purposes.
16544 * @returns {object} Promise manager.
16545 */
16546function qFactory(nextTick, exceptionHandler) {
16547
16548  /**
16549   * @ngdoc method
16550   * @name $q#defer
16551   * @kind function
16552   *
16553   * @description
16554   * Creates a `Deferred` object which represents a task which will finish in the future.
16555   *
16556   * @returns {Deferred} Returns a new instance of deferred.
16557   */
16558  var defer = function() {
16559    var pending = [],
16560        value, deferred;
16561
16562    deferred = {
16563
16564      resolve: function(val) {
16565        if (pending) {
16566          var callbacks = pending;
16567          pending = undefined;
16568          value = ref(val);
16569
16570          if (callbacks.length) {
16571            nextTick(function() {
16572              var callback;
16573              for (var i = 0, ii = callbacks.length; i < ii; i++) {
16574                callback = callbacks[i];
16575                value.then(callback[0], callback[1], callback[2]);
16576              }
16577            });
16578          }
16579        }
16580      },
16581
16582
16583      reject: function(reason) {
16584        deferred.resolve(createInternalRejectedPromise(reason));
16585      },
16586
16587
16588      notify: function(progress) {
16589        if (pending) {
16590          var callbacks = pending;
16591
16592          if (pending.length) {
16593            nextTick(function() {
16594              var callback;
16595              for (var i = 0, ii = callbacks.length; i < ii; i++) {
16596                callback = callbacks[i];
16597                callback[2](progress);
16598              }
16599            });
16600          }
16601        }
16602      },
16603
16604
16605      promise: {
16606        then: function(callback, errback, progressback) {
16607          var result = defer();
16608
16609          var wrappedCallback = function(value) {
16610            try {
16611              result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
16612            } catch(e) {
16613              result.reject(e);
16614              exceptionHandler(e);
16615            }
16616          };
16617
16618          var wrappedErrback = function(reason) {
16619            try {
16620              result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
16621            } catch(e) {
16622              result.reject(e);
16623              exceptionHandler(e);
16624            }
16625          };
16626
16627          var wrappedProgressback = function(progress) {
16628            try {
16629              result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
16630            } catch(e) {
16631              exceptionHandler(e);
16632            }
16633          };
16634
16635          if (pending) {
16636            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
16637          } else {
16638            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
16639          }
16640
16641          return result.promise;
16642        },
16643
16644        "catch": function(callback) {
16645          return this.then(null, callback);
16646        },
16647
16648        "finally": function(callback) {
16649
16650          function makePromise(value, resolved) {
16651            var result = defer();
16652            if (resolved) {
16653              result.resolve(value);
16654            } else {
16655              result.reject(value);
16656            }
16657            return result.promise;
16658          }
16659
16660          function handleCallback(value, isResolved) {
16661            var callbackOutput = null;
16662            try {
16663              callbackOutput = (callback ||defaultCallback)();
16664            } catch(e) {
16665              return makePromise(e, false);
16666            }
16667            if (isPromiseLike(callbackOutput)) {
16668              return callbackOutput.then(function() {
16669                return makePromise(value, isResolved);
16670              }, function(error) {
16671                return makePromise(error, false);
16672              });
16673            } else {
16674              return makePromise(value, isResolved);
16675            }
16676          }
16677
16678          return this.then(function(value) {
16679            return handleCallback(value, true);
16680          }, function(error) {
16681            return handleCallback(error, false);
16682          });
16683        }
16684      }
16685    };
16686
16687    return deferred;
16688  };
16689
16690
16691  var ref = function(value) {
16692    if (isPromiseLike(value)) return value;
16693    return {
16694      then: function(callback) {
16695        var result = defer();
16696        nextTick(function() {
16697          result.resolve(callback(value));
16698        });
16699        return result.promise;
16700      }
16701    };
16702  };
16703
16704
16705  /**
16706   * @ngdoc method
16707   * @name $q#reject
16708   * @kind function
16709   *
16710   * @description
16711   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
16712   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
16713   * a promise chain, you don't need to worry about it.
16714   *
16715   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
16716   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
16717   * a promise error callback and you want to forward the error to the promise derived from the
16718   * current promise, you have to "rethrow" the error by returning a rejection constructed via
16719   * `reject`.
16720   *
16721   * ```js
16722   *   promiseB = promiseA.then(function(result) {
16723   *     // success: do something and resolve promiseB
16724   *     //          with the old or a new result
16725   *     return result;
16726   *   }, function(reason) {
16727   *     // error: handle the error if possible and
16728   *     //        resolve promiseB with newPromiseOrValue,
16729   *     //        otherwise forward the rejection to promiseB
16730   *     if (canHandle(reason)) {
16731   *      // handle the error and recover
16732   *      return newPromiseOrValue;
16733   *     }
16734   *     return $q.reject(reason);
16735   *   });
16736   * ```
16737   *
16738   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
16739   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
16740   */
16741  var reject = function(reason) {
16742    var result = defer();
16743    result.reject(reason);
16744    return result.promise;
16745  };
16746
16747  var createInternalRejectedPromise = function(reason) {
16748    return {
16749      then: function(callback, errback) {
16750        var result = defer();
16751        nextTick(function() {
16752          try {
16753            result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
16754          } catch(e) {
16755            result.reject(e);
16756            exceptionHandler(e);
16757          }
16758        });
16759        return result.promise;
16760      }
16761    };
16762  };
16763
16764
16765  /**
16766   * @ngdoc method
16767   * @name $q#when
16768   * @kind function
16769   *
16770   * @description
16771   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
16772   * This is useful when you are dealing with an object that might or might not be a promise, or if
16773   * the promise comes from a source that can't be trusted.
16774   *
16775   * @param {*} value Value or a promise
16776   * @returns {Promise} Returns a promise of the passed value or promise
16777   */
16778  var when = function(value, callback, errback, progressback) {
16779    var result = defer(),
16780        done;
16781
16782    var wrappedCallback = function(value) {
16783      try {
16784        return (isFunction(callback) ? callback : defaultCallback)(value);
16785      } catch (e) {
16786        exceptionHandler(e);
16787        return reject(e);
16788      }
16789    };
16790
16791    var wrappedErrback = function(reason) {
16792      try {
16793        return (isFunction(errback) ? errback : defaultErrback)(reason);
16794      } catch (e) {
16795        exceptionHandler(e);
16796        return reject(e);
16797      }
16798    };
16799
16800    var wrappedProgressback = function(progress) {
16801      try {
16802        return (isFunction(progressback) ? progressback : defaultCallback)(progress);
16803      } catch (e) {
16804        exceptionHandler(e);
16805      }
16806    };
16807
16808    nextTick(function() {
16809      ref(value).then(function(value) {
16810        if (done) return;
16811        done = true;
16812        result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
16813      }, function(reason) {
16814        if (done) return;
16815        done = true;
16816        result.resolve(wrappedErrback(reason));
16817      }, function(progress) {
16818        if (done) return;
16819        result.notify(wrappedProgressback(progress));
16820      });
16821    });
16822
16823    return result.promise;
16824  };
16825
16826
16827  function defaultCallback(value) {
16828    return value;
16829  }
16830
16831
16832  function defaultErrback(reason) {
16833    return reject(reason);
16834  }
16835
16836
16837  /**
16838   * @ngdoc method
16839   * @name $q#all
16840   * @kind function
16841   *
16842   * @description
16843   * Combines multiple promises into a single promise that is resolved when all of the input
16844   * promises are resolved.
16845   *
16846   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
16847   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
16848   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
16849   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
16850   *   with the same rejection value.
16851   */
16852  function all(promises) {
16853    var deferred = defer(),
16854        counter = 0,
16855        results = isArray(promises) ? [] : {};
16856
16857    forEach(promises, function(promise, key) {
16858      counter++;
16859      ref(promise).then(function(value) {
16860        if (results.hasOwnProperty(key)) return;
16861        results[key] = value;
16862        if (!(--counter)) deferred.resolve(results);
16863      }, function(reason) {
16864        if (results.hasOwnProperty(key)) return;
16865        deferred.reject(reason);
16866      });
16867    });
16868
16869    if (counter === 0) {
16870      deferred.resolve(results);
16871    }
16872
16873    return deferred.promise;
16874  }
16875
16876  return {
16877    defer: defer,
16878    reject: reject,
16879    when: when,
16880    all: all
16881  };
16882}
16883
16884function $$RAFProvider(){ //rAF
16885  this.$get = ['$window', '$timeout', function($window, $timeout) {
16886    var requestAnimationFrame = $window.requestAnimationFrame ||
16887                                $window.webkitRequestAnimationFrame ||
16888                                $window.mozRequestAnimationFrame;
16889
16890    var cancelAnimationFrame = $window.cancelAnimationFrame ||
16891                               $window.webkitCancelAnimationFrame ||
16892                               $window.mozCancelAnimationFrame ||
16893                               $window.webkitCancelRequestAnimationFrame;
16894
16895    var rafSupported = !!requestAnimationFrame;
16896    var raf = rafSupported
16897      ? function(fn) {
16898          var id = requestAnimationFrame(fn);
16899          return function() {
16900            cancelAnimationFrame(id);
16901          };
16902        }
16903      : function(fn) {
16904          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
16905          return function() {
16906            $timeout.cancel(timer);
16907          };
16908        };
16909
16910    raf.supported = rafSupported;
16911
16912    return raf;
16913  }];
16914}
16915
16916/**
16917 * DESIGN NOTES
16918 *
16919 * The design decisions behind the scope are heavily favored for speed and memory consumption.
16920 *
16921 * The typical use of scope is to watch the expressions, which most of the time return the same
16922 * value as last time so we optimize the operation.
16923 *
16924 * Closures construction is expensive in terms of speed as well as memory:
16925 *   - No closures, instead use prototypical inheritance for API
16926 *   - Internal state needs to be stored on scope directly, which means that private state is
16927 *     exposed as $$____ properties
16928 *
16929 * Loop operations are optimized by using while(count--) { ... }
16930 *   - this means that in order to keep the same order of execution as addition we have to add
16931 *     items to the array at the beginning (unshift) instead of at the end (push)
16932 *
16933 * Child scopes are created and removed often
16934 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
16935 *
16936 * There are few watches then a lot of observers. This is why you don't want the observer to be
16937 * implemented in the same way as watch. Watch requires return of initialization function which
16938 * are expensive to construct.
16939 */
16940
16941
16942/**
16943 * @ngdoc provider
16944 * @name $rootScopeProvider
16945 * @description
16946 *
16947 * Provider for the $rootScope service.
16948 */
16949
16950/**
16951 * @ngdoc method
16952 * @name $rootScopeProvider#digestTtl
16953 * @description
16954 *
16955 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
16956 * assuming that the model is unstable.
16957 *
16958 * The current default is 10 iterations.
16959 *
16960 * In complex applications it's possible that the dependencies between `$watch`s will result in
16961 * several digest iterations. However if an application needs more than the default 10 digest
16962 * iterations for its model to stabilize then you should investigate what is causing the model to
16963 * continuously change during the digest.
16964 *
16965 * Increasing the TTL could have performance implications, so you should not change it without
16966 * proper justification.
16967 *
16968 * @param {number} limit The number of digest iterations.
16969 */
16970
16971
16972/**
16973 * @ngdoc service
16974 * @name $rootScope
16975 * @description
16976 *
16977 * Every application has a single root {@link ng.$rootScope.Scope scope}.
16978 * All other scopes are descendant scopes of the root scope. Scopes provide separation
16979 * between the model and the view, via a mechanism for watching the model for changes.
16980 * They also provide an event emission/broadcast and subscription facility. See the
16981 * {@link guide/scope developer guide on scopes}.
16982 */
16983function $RootScopeProvider(){
16984  var TTL = 10;
16985  var $rootScopeMinErr = minErr('$rootScope');
16986  var lastDirtyWatch = null;
16987
16988  this.digestTtl = function(value) {
16989    if (arguments.length) {
16990      TTL = value;
16991    }
16992    return TTL;
16993  };
16994
16995  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
16996      function( $injector,   $exceptionHandler,   $parse,   $browser) {
16997
16998    /**
16999     * @ngdoc type
17000     * @name $rootScope.Scope
17001     *
17002     * @description
17003     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
17004     * {@link auto.$injector $injector}. Child scopes are created using the
17005     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
17006     * compiled HTML template is executed.)
17007     *
17008     * Here is a simple scope snippet to show how you can interact with the scope.
17009     * ```html
17010     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
17011     * ```
17012     *
17013     * # Inheritance
17014     * A scope can inherit from a parent scope, as in this example:
17015     * ```js
17016         var parent = $rootScope;
17017         var child = parent.$new();
17018
17019         parent.salutation = "Hello";
17020         child.name = "World";
17021         expect(child.salutation).toEqual('Hello');
17022
17023         child.salutation = "Welcome";
17024         expect(child.salutation).toEqual('Welcome');
17025         expect(parent.salutation).toEqual('Hello');
17026     * ```
17027     *
17028     *
17029     * @param {Object.<string, function()>=} providers Map of service factory which need to be
17030     *                                       provided for the current scope. Defaults to {@link ng}.
17031     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
17032     *                              append/override services provided by `providers`. This is handy
17033     *                              when unit-testing and having the need to override a default
17034     *                              service.
17035     * @returns {Object} Newly created scope.
17036     *
17037     */
17038    function Scope() {
17039      this.$id = nextUid();
17040      this.$$phase = this.$parent = this.$$watchers =
17041                     this.$$nextSibling = this.$$prevSibling =
17042                     this.$$childHead = this.$$childTail = null;
17043      this['this'] = this.$root =  this;
17044      this.$$destroyed = false;
17045      this.$$asyncQueue = [];
17046      this.$$postDigestQueue = [];
17047      this.$$listeners = {};
17048      this.$$listenerCount = {};
17049      this.$$isolateBindings = {};
17050    }
17051
17052    /**
17053     * @ngdoc property
17054     * @name $rootScope.Scope#$id
17055     *
17056     * @description
17057     * Unique scope ID (monotonically increasing) useful for debugging.
17058     */
17059
17060     /**
17061      * @ngdoc property
17062      * @name $rootScope.Scope#$parent
17063      *
17064      * @description
17065      * Reference to the parent scope.
17066      */
17067
17068      /**
17069       * @ngdoc property
17070       * @name $rootScope.Scope#$root
17071       *
17072       * @description
17073       * Reference to the root scope.
17074       */
17075
17076    Scope.prototype = {
17077      constructor: Scope,
17078      /**
17079       * @ngdoc method
17080       * @name $rootScope.Scope#$new
17081       * @kind function
17082       *
17083       * @description
17084       * Creates a new child {@link ng.$rootScope.Scope scope}.
17085       *
17086       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
17087       * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
17088       *
17089       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
17090       * desired for the scope and its child scopes to be permanently detached from the parent and
17091       * thus stop participating in model change detection and listener notification by invoking.
17092       *
17093       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
17094       *         parent scope. The scope is isolated, as it can not see parent scope properties.
17095       *         When creating widgets, it is useful for the widget to not accidentally read parent
17096       *         state.
17097       *
17098       * @returns {Object} The newly created child scope.
17099       *
17100       */
17101      $new: function(isolate) {
17102        var ChildScope,
17103            child;
17104
17105        if (isolate) {
17106          child = new Scope();
17107          child.$root = this.$root;
17108          // ensure that there is just one async queue per $rootScope and its children
17109          child.$$asyncQueue = this.$$asyncQueue;
17110          child.$$postDigestQueue = this.$$postDigestQueue;
17111        } else {
17112          // Only create a child scope class if somebody asks for one,
17113          // but cache it to allow the VM to optimize lookups.
17114          if (!this.$$childScopeClass) {
17115            this.$$childScopeClass = function() {
17116              this.$$watchers = this.$$nextSibling =
17117                  this.$$childHead = this.$$childTail = null;
17118              this.$$listeners = {};
17119              this.$$listenerCount = {};
17120              this.$id = nextUid();
17121              this.$$childScopeClass = null;
17122            };
17123            this.$$childScopeClass.prototype = this;
17124          }
17125          child = new this.$$childScopeClass();
17126        }
17127        child['this'] = child;
17128        child.$parent = this;
17129        child.$$prevSibling = this.$$childTail;
17130        if (this.$$childHead) {
17131          this.$$childTail.$$nextSibling = child;
17132          this.$$childTail = child;
17133        } else {
17134          this.$$childHead = this.$$childTail = child;
17135        }
17136        return child;
17137      },
17138
17139      /**
17140       * @ngdoc method
17141       * @name $rootScope.Scope#$watch
17142       * @kind function
17143       *
17144       * @description
17145       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
17146       *
17147       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
17148       *   $digest()} and should return the value that will be watched. (Since
17149       *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
17150       *   `watchExpression` can execute multiple times per
17151       *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
17152       * - The `listener` is called only when the value from the current `watchExpression` and the
17153       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
17154       *   see below). Inequality is determined according to reference inequality,
17155       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
17156       *    via the `!==` Javascript operator, unless `objectEquality == true`
17157       *   (see next point)
17158       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
17159       *   according to the {@link angular.equals} function. To save the value of the object for
17160       *   later comparison, the {@link angular.copy} function is used. This therefore means that
17161       *   watching complex objects will have adverse memory and performance implications.
17162       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
17163       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
17164       *   iteration limit is 10 to prevent an infinite loop deadlock.
17165       *
17166       *
17167       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
17168       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
17169       * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
17170       * change is detected, be prepared for multiple calls to your listener.)
17171       *
17172       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
17173       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
17174       * watcher. In rare cases, this is undesirable because the listener is called when the result
17175       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
17176       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
17177       * listener was called due to initialization.
17178       *
17179       * The example below contains an illustration of using a function as your $watch listener
17180       *
17181       *
17182       * # Example
17183       * ```js
17184           // let's assume that scope was dependency injected as the $rootScope
17185           var scope = $rootScope;
17186           scope.name = 'misko';
17187           scope.counter = 0;
17188
17189           expect(scope.counter).toEqual(0);
17190           scope.$watch('name', function(newValue, oldValue) {
17191             scope.counter = scope.counter + 1;
17192           });
17193           expect(scope.counter).toEqual(0);
17194
17195           scope.$digest();
17196           // the listener is always called during the first $digest loop after it was registered
17197           expect(scope.counter).toEqual(1);
17198
17199           scope.$digest();
17200           // but now it will not be called unless the value changes
17201           expect(scope.counter).toEqual(1);
17202
17203           scope.name = 'adam';
17204           scope.$digest();
17205           expect(scope.counter).toEqual(2);
17206
17207
17208
17209           // Using a listener function
17210           var food;
17211           scope.foodCounter = 0;
17212           expect(scope.foodCounter).toEqual(0);
17213           scope.$watch(
17214             // This is the listener function
17215             function() { return food; },
17216             // This is the change handler
17217             function(newValue, oldValue) {
17218               if ( newValue !== oldValue ) {
17219                 // Only increment the counter if the value changed
17220                 scope.foodCounter = scope.foodCounter + 1;
17221               }
17222             }
17223           );
17224           // No digest has been run so the counter will be zero
17225           expect(scope.foodCounter).toEqual(0);
17226
17227           // Run the digest but since food has not changed count will still be zero
17228           scope.$digest();
17229           expect(scope.foodCounter).toEqual(0);
17230
17231           // Update food and run digest.  Now the counter will increment
17232           food = 'cheeseburger';
17233           scope.$digest();
17234           expect(scope.foodCounter).toEqual(1);
17235
17236       * ```
17237       *
17238       *
17239       *
17240       * @param {(function()|string)} watchExpression Expression that is evaluated on each
17241       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
17242       *    a call to the `listener`.
17243       *
17244       *    - `string`: Evaluated as {@link guide/expression expression}
17245       *    - `function(scope)`: called with current `scope` as a parameter.
17246       * @param {(function()|string)=} listener Callback called whenever the return value of
17247       *   the `watchExpression` changes.
17248       *
17249       *    - `string`: Evaluated as {@link guide/expression expression}
17250       *    - `function(newValue, oldValue, scope)`: called with current and previous values as
17251       *      parameters.
17252       *
17253       * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
17254       *     comparing for reference equality.
17255       * @returns {function()} Returns a deregistration function for this listener.
17256       */
17257      $watch: function(watchExp, listener, objectEquality) {
17258        var scope = this,
17259            get = compileToFn(watchExp, 'watch'),
17260            array = scope.$$watchers,
17261            watcher = {
17262              fn: listener,
17263              last: initWatchVal,
17264              get: get,
17265              exp: watchExp,
17266              eq: !!objectEquality
17267            };
17268
17269        lastDirtyWatch = null;
17270
17271        // in the case user pass string, we need to compile it, do we really need this ?
17272        if (!isFunction(listener)) {
17273          var listenFn = compileToFn(listener || noop, 'listener');
17274          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
17275        }
17276
17277        if (typeof watchExp == 'string' && get.constant) {
17278          var originalFn = watcher.fn;
17279          watcher.fn = function(newVal, oldVal, scope) {
17280            originalFn.call(this, newVal, oldVal, scope);
17281            arrayRemove(array, watcher);
17282          };
17283        }
17284
17285        if (!array) {
17286          array = scope.$$watchers = [];
17287        }
17288        // we use unshift since we use a while loop in $digest for speed.
17289        // the while loop reads in reverse order.
17290        array.unshift(watcher);
17291
17292        return function deregisterWatch() {
17293          arrayRemove(array, watcher);
17294          lastDirtyWatch = null;
17295        };
17296      },
17297
17298
17299      /**
17300       * @ngdoc method
17301       * @name $rootScope.Scope#$watchCollection
17302       * @kind function
17303       *
17304       * @description
17305       * Shallow watches the properties of an object and fires whenever any of the properties change
17306       * (for arrays, this implies watching the array items; for object maps, this implies watching
17307       * the properties). If a change is detected, the `listener` callback is fired.
17308       *
17309       * - The `obj` collection is observed via standard $watch operation and is examined on every
17310       *   call to $digest() to see if any items have been added, removed, or moved.
17311       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
17312       *   adding, removing, and moving items belonging to an object or array.
17313       *
17314       *
17315       * # Example
17316       * ```js
17317          $scope.names = ['igor', 'matias', 'misko', 'james'];
17318          $scope.dataCount = 4;
17319
17320          $scope.$watchCollection('names', function(newNames, oldNames) {
17321            $scope.dataCount = newNames.length;
17322          });
17323
17324          expect($scope.dataCount).toEqual(4);
17325          $scope.$digest();
17326
17327          //still at 4 ... no changes
17328          expect($scope.dataCount).toEqual(4);
17329
17330          $scope.names.pop();
17331          $scope.$digest();
17332
17333          //now there's been a change
17334          expect($scope.dataCount).toEqual(3);
17335       * ```
17336       *
17337       *
17338       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
17339       *    expression value should evaluate to an object or an array which is observed on each
17340       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
17341       *    collection will trigger a call to the `listener`.
17342       *
17343       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
17344       *    when a change is detected.
17345       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
17346       *    - The `oldCollection` object is a copy of the former collection data.
17347       *      Due to performance considerations, the`oldCollection` value is computed only if the
17348       *      `listener` function declares two or more arguments.
17349       *    - The `scope` argument refers to the current scope.
17350       *
17351       * @returns {function()} Returns a de-registration function for this listener. When the
17352       *    de-registration function is executed, the internal watch operation is terminated.
17353       */
17354      $watchCollection: function(obj, listener) {
17355        var self = this;
17356        // the current value, updated on each dirty-check run
17357        var newValue;
17358        // a shallow copy of the newValue from the last dirty-check run,
17359        // updated to match newValue during dirty-check run
17360        var oldValue;
17361        // a shallow copy of the newValue from when the last change happened
17362        var veryOldValue;
17363        // only track veryOldValue if the listener is asking for it
17364        var trackVeryOldValue = (listener.length > 1);
17365        var changeDetected = 0;
17366        var objGetter = $parse(obj);
17367        var internalArray = [];
17368        var internalObject = {};
17369        var initRun = true;
17370        var oldLength = 0;
17371
17372        function $watchCollectionWatch() {
17373          newValue = objGetter(self);
17374          var newLength, key, bothNaN;
17375
17376          if (!isObject(newValue)) { // if primitive
17377            if (oldValue !== newValue) {
17378              oldValue = newValue;
17379              changeDetected++;
17380            }
17381          } else if (isArrayLike(newValue)) {
17382            if (oldValue !== internalArray) {
17383              // we are transitioning from something which was not an array into array.
17384              oldValue = internalArray;
17385              oldLength = oldValue.length = 0;
17386              changeDetected++;
17387            }
17388
17389            newLength = newValue.length;
17390
17391            if (oldLength !== newLength) {
17392              // if lengths do not match we need to trigger change notification
17393              changeDetected++;
17394              oldValue.length = oldLength = newLength;
17395            }
17396            // copy the items to oldValue and look for changes.
17397            for (var i = 0; i < newLength; i++) {
17398              bothNaN = (oldValue[i] !== oldValue[i]) &&
17399                  (newValue[i] !== newValue[i]);
17400              if (!bothNaN && (oldValue[i] !== newValue[i])) {
17401                changeDetected++;
17402                oldValue[i] = newValue[i];
17403              }
17404            }
17405          } else {
17406            if (oldValue !== internalObject) {
17407              // we are transitioning from something which was not an object into object.
17408              oldValue = internalObject = {};
17409              oldLength = 0;
17410              changeDetected++;
17411            }
17412            // copy the items to oldValue and look for changes.
17413            newLength = 0;
17414            for (key in newValue) {
17415              if (newValue.hasOwnProperty(key)) {
17416                newLength++;
17417                if (oldValue.hasOwnProperty(key)) {
17418                  bothNaN = (oldValue[key] !== oldValue[key]) &&
17419                      (newValue[key] !== newValue[key]);
17420                  if (!bothNaN && (oldValue[key] !== newValue[key])) {
17421                    changeDetected++;
17422                    oldValue[key] = newValue[key];
17423                  }
17424                } else {
17425                  oldLength++;
17426                  oldValue[key] = newValue[key];
17427                  changeDetected++;
17428                }
17429              }
17430            }
17431            if (oldLength > newLength) {
17432              // we used to have more keys, need to find them and destroy them.
17433              changeDetected++;
17434              for(key in oldValue) {
17435                if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
17436                  oldLength--;
17437                  delete oldValue[key];
17438                }
17439              }
17440            }
17441          }
17442          return changeDetected;
17443        }
17444
17445        function $watchCollectionAction() {
17446          if (initRun) {
17447            initRun = false;
17448            listener(newValue, newValue, self);
17449          } else {
17450            listener(newValue, veryOldValue, self);
17451          }
17452
17453          // make a copy for the next time a collection is changed
17454          if (trackVeryOldValue) {
17455            if (!isObject(newValue)) {
17456              //primitive
17457              veryOldValue = newValue;
17458            } else if (isArrayLike(newValue)) {
17459              veryOldValue = new Array(newValue.length);
17460              for (var i = 0; i < newValue.length; i++) {
17461                veryOldValue[i] = newValue[i];
17462              }
17463            } else { // if object
17464              veryOldValue = {};
17465              for (var key in newValue) {
17466                if (hasOwnProperty.call(newValue, key)) {
17467                  veryOldValue[key] = newValue[key];
17468                }
17469              }
17470            }
17471          }
17472        }
17473
17474        return this.$watch($watchCollectionWatch, $watchCollectionAction);
17475      },
17476
17477      /**
17478       * @ngdoc method
17479       * @name $rootScope.Scope#$digest
17480       * @kind function
17481       *
17482       * @description
17483       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
17484       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
17485       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
17486       * until no more listeners are firing. This means that it is possible to get into an infinite
17487       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
17488       * iterations exceeds 10.
17489       *
17490       * Usually, you don't call `$digest()` directly in
17491       * {@link ng.directive:ngController controllers} or in
17492       * {@link ng.$compileProvider#directive directives}.
17493       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
17494       * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
17495       *
17496       * If you want to be notified whenever `$digest()` is called,
17497       * you can register a `watchExpression` function with
17498       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
17499       *
17500       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
17501       *
17502       * # Example
17503       * ```js
17504           var scope = ...;
17505           scope.name = 'misko';
17506           scope.counter = 0;
17507
17508           expect(scope.counter).toEqual(0);
17509           scope.$watch('name', function(newValue, oldValue) {
17510             scope.counter = scope.counter + 1;
17511           });
17512           expect(scope.counter).toEqual(0);
17513
17514           scope.$digest();
17515           // the listener is always called during the first $digest loop after it was registered
17516           expect(scope.counter).toEqual(1);
17517
17518           scope.$digest();
17519           // but now it will not be called unless the value changes
17520           expect(scope.counter).toEqual(1);
17521
17522           scope.name = 'adam';
17523           scope.$digest();
17524           expect(scope.counter).toEqual(2);
17525       * ```
17526       *
17527       */
17528      $digest: function() {
17529        var watch, value, last,
17530            watchers,
17531            asyncQueue = this.$$asyncQueue,
17532            postDigestQueue = this.$$postDigestQueue,
17533            length,
17534            dirty, ttl = TTL,
17535            next, current, target = this,
17536            watchLog = [],
17537            logIdx, logMsg, asyncTask;
17538
17539        beginPhase('$digest');
17540        // Check for changes to browser url that happened in sync before the call to $digest
17541        $browser.$$checkUrlChange();
17542
17543        lastDirtyWatch = null;
17544
17545        do { // "while dirty" loop
17546          dirty = false;
17547          current = target;
17548
17549          while(asyncQueue.length) {
17550            try {
17551              asyncTask = asyncQueue.shift();
17552              asyncTask.scope.$eval(asyncTask.expression);
17553            } catch (e) {
17554              clearPhase();
17555              $exceptionHandler(e);
17556            }
17557            lastDirtyWatch = null;
17558          }
17559
17560          traverseScopesLoop:
17561          do { // "traverse the scopes" loop
17562            if ((watchers = current.$$watchers)) {
17563              // process our watches
17564              length = watchers.length;
17565              while (length--) {
17566                try {
17567                  watch = watchers[length];
17568                  // Most common watches are on primitives, in which case we can short
17569                  // circuit it with === operator, only when === fails do we use .equals
17570                  if (watch) {
17571                    if ((value = watch.get(current)) !== (last = watch.last) &&
17572                        !(watch.eq
17573                            ? equals(value, last)
17574                            : (typeof value === 'number' && typeof last === 'number'
17575                               && isNaN(value) && isNaN(last)))) {
17576                      dirty = true;
17577                      lastDirtyWatch = watch;
17578                      watch.last = watch.eq ? copy(value, null) : value;
17579                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
17580                      if (ttl < 5) {
17581                        logIdx = 4 - ttl;
17582                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
17583                        logMsg = (isFunction(watch.exp))
17584                            ? 'fn: ' + (watch.exp.name || watch.exp.toString())
17585                            : watch.exp;
17586                        logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
17587                        watchLog[logIdx].push(logMsg);
17588                      }
17589                    } else if (watch === lastDirtyWatch) {
17590                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
17591                      // have already been tested.
17592                      dirty = false;
17593                      break traverseScopesLoop;
17594                    }
17595                  }
17596                } catch (e) {
17597                  clearPhase();
17598                  $exceptionHandler(e);
17599                }
17600              }
17601            }
17602
17603            // Insanity Warning: scope depth-first traversal
17604            // yes, this code is a bit crazy, but it works and we have tests to prove it!
17605            // this piece should be kept in sync with the traversal in $broadcast
17606            if (!(next = (current.$$childHead ||
17607                (current !== target && current.$$nextSibling)))) {
17608              while(current !== target && !(next = current.$$nextSibling)) {
17609                current = current.$parent;
17610              }
17611            }
17612          } while ((current = next));
17613
17614          // `break traverseScopesLoop;` takes us to here
17615
17616          if((dirty || asyncQueue.length) && !(ttl--)) {
17617            clearPhase();
17618            throw $rootScopeMinErr('infdig',
17619                '{0} $digest() iterations reached. Aborting!\n' +
17620                'Watchers fired in the last 5 iterations: {1}',
17621                TTL, toJson(watchLog));
17622          }
17623
17624        } while (dirty || asyncQueue.length);
17625
17626        clearPhase();
17627
17628        while(postDigestQueue.length) {
17629          try {
17630            postDigestQueue.shift()();
17631          } catch (e) {
17632            $exceptionHandler(e);
17633          }
17634        }
17635      },
17636
17637
17638      /**
17639       * @ngdoc event
17640       * @name $rootScope.Scope#$destroy
17641       * @eventType broadcast on scope being destroyed
17642       *
17643       * @description
17644       * Broadcasted when a scope and its children are being destroyed.
17645       *
17646       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
17647       * clean up DOM bindings before an element is removed from the DOM.
17648       */
17649
17650      /**
17651       * @ngdoc method
17652       * @name $rootScope.Scope#$destroy
17653       * @kind function
17654       *
17655       * @description
17656       * Removes the current scope (and all of its children) from the parent scope. Removal implies
17657       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
17658       * propagate to the current scope and its children. Removal also implies that the current
17659       * scope is eligible for garbage collection.
17660       *
17661       * The `$destroy()` is usually used by directives such as
17662       * {@link ng.directive:ngRepeat ngRepeat} for managing the
17663       * unrolling of the loop.
17664       *
17665       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
17666       * Application code can register a `$destroy` event handler that will give it a chance to
17667       * perform any necessary cleanup.
17668       *
17669       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
17670       * clean up DOM bindings before an element is removed from the DOM.
17671       */
17672      $destroy: function() {
17673        // we can't destroy the root scope or a scope that has been already destroyed
17674        if (this.$$destroyed) return;
17675        var parent = this.$parent;
17676
17677        this.$broadcast('$destroy');
17678        this.$$destroyed = true;
17679        if (this === $rootScope) return;
17680
17681        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
17682
17683        // sever all the references to parent scopes (after this cleanup, the current scope should
17684        // not be retained by any of our references and should be eligible for garbage collection)
17685        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
17686        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
17687        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
17688        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
17689
17690
17691        // All of the code below is bogus code that works around V8's memory leak via optimized code
17692        // and inline caches.
17693        //
17694        // see:
17695        // - https://code.google.com/p/v8/issues/detail?id=2073#c26
17696        // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
17697        // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
17698
17699        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
17700            this.$$childTail = this.$root = null;
17701
17702        // don't reset these to null in case some async task tries to register a listener/watch/task
17703        this.$$listeners = {};
17704        this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
17705
17706        // prevent NPEs since these methods have references to properties we nulled out
17707        this.$destroy = this.$digest = this.$apply = noop;
17708        this.$on = this.$watch = function() { return noop; };
17709      },
17710
17711      /**
17712       * @ngdoc method
17713       * @name $rootScope.Scope#$eval
17714       * @kind function
17715       *
17716       * @description
17717       * Executes the `expression` on the current scope and returns the result. Any exceptions in
17718       * the expression are propagated (uncaught). This is useful when evaluating Angular
17719       * expressions.
17720       *
17721       * # Example
17722       * ```js
17723           var scope = ng.$rootScope.Scope();
17724           scope.a = 1;
17725           scope.b = 2;
17726
17727           expect(scope.$eval('a+b')).toEqual(3);
17728           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
17729       * ```
17730       *
17731       * @param {(string|function())=} expression An angular expression to be executed.
17732       *
17733       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
17734       *    - `function(scope)`: execute the function with the current `scope` parameter.
17735       *
17736       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
17737       * @returns {*} The result of evaluating the expression.
17738       */
17739      $eval: function(expr, locals) {
17740        return $parse(expr)(this, locals);
17741      },
17742
17743      /**
17744       * @ngdoc method
17745       * @name $rootScope.Scope#$evalAsync
17746       * @kind function
17747       *
17748       * @description
17749       * Executes the expression on the current scope at a later point in time.
17750       *
17751       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
17752       * that:
17753       *
17754       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
17755       *     rendering).
17756       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
17757       *     `expression` execution.
17758       *
17759       * Any exceptions from the execution of the expression are forwarded to the
17760       * {@link ng.$exceptionHandler $exceptionHandler} service.
17761       *
17762       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
17763       * will be scheduled. However, it is encouraged to always call code that changes the model
17764       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
17765       *
17766       * @param {(string|function())=} expression An angular expression to be executed.
17767       *
17768       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
17769       *    - `function(scope)`: execute the function with the current `scope` parameter.
17770       *
17771       */
17772      $evalAsync: function(expr) {
17773        // if we are outside of an $digest loop and this is the first time we are scheduling async
17774        // task also schedule async auto-flush
17775        if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
17776          $browser.defer(function() {
17777            if ($rootScope.$$asyncQueue.length) {
17778              $rootScope.$digest();
17779            }
17780          });
17781        }
17782
17783        this.$$asyncQueue.push({scope: this, expression: expr});
17784      },
17785
17786      $$postDigest : function(fn) {
17787        this.$$postDigestQueue.push(fn);
17788      },
17789
17790      /**
17791       * @ngdoc method
17792       * @name $rootScope.Scope#$apply
17793       * @kind function
17794       *
17795       * @description
17796       * `$apply()` is used to execute an expression in angular from outside of the angular
17797       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
17798       * Because we are calling into the angular framework we need to perform proper scope life
17799       * cycle of {@link ng.$exceptionHandler exception handling},
17800       * {@link ng.$rootScope.Scope#$digest executing watches}.
17801       *
17802       * ## Life cycle
17803       *
17804       * # Pseudo-Code of `$apply()`
17805       * ```js
17806           function $apply(expr) {
17807             try {
17808               return $eval(expr);
17809             } catch (e) {
17810               $exceptionHandler(e);
17811             } finally {
17812               $root.$digest();
17813             }
17814           }
17815       * ```
17816       *
17817       *
17818       * Scope's `$apply()` method transitions through the following stages:
17819       *
17820       * 1. The {@link guide/expression expression} is executed using the
17821       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
17822       * 2. Any exceptions from the execution of the expression are forwarded to the
17823       *    {@link ng.$exceptionHandler $exceptionHandler} service.
17824       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
17825       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
17826       *
17827       *
17828       * @param {(string|function())=} exp An angular expression to be executed.
17829       *
17830       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
17831       *    - `function(scope)`: execute the function with current `scope` parameter.
17832       *
17833       * @returns {*} The result of evaluating the expression.
17834       */
17835      $apply: function(expr) {
17836        try {
17837          beginPhase('$apply');
17838          return this.$eval(expr);
17839        } catch (e) {
17840          $exceptionHandler(e);
17841        } finally {
17842          clearPhase();
17843          try {
17844            $rootScope.$digest();
17845          } catch (e) {
17846            $exceptionHandler(e);
17847            throw e;
17848          }
17849        }
17850      },
17851
17852      /**
17853       * @ngdoc method
17854       * @name $rootScope.Scope#$on
17855       * @kind function
17856       *
17857       * @description
17858       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
17859       * discussion of event life cycle.
17860       *
17861       * The event listener function format is: `function(event, args...)`. The `event` object
17862       * passed into the listener has the following attributes:
17863       *
17864       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
17865       *     `$broadcast`-ed.
17866       *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
17867       *   - `name` - `{string}`: name of the event.
17868       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
17869       *     further event propagation (available only for events that were `$emit`-ed).
17870       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
17871       *     to true.
17872       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
17873       *
17874       * @param {string} name Event name to listen on.
17875       * @param {function(event, ...args)} listener Function to call when the event is emitted.
17876       * @returns {function()} Returns a deregistration function for this listener.
17877       */
17878      $on: function(name, listener) {
17879        var namedListeners = this.$$listeners[name];
17880        if (!namedListeners) {
17881          this.$$listeners[name] = namedListeners = [];
17882        }
17883        namedListeners.push(listener);
17884
17885        var current = this;
17886        do {
17887          if (!current.$$listenerCount[name]) {
17888            current.$$listenerCount[name] = 0;
17889          }
17890          current.$$listenerCount[name]++;
17891        } while ((current = current.$parent));
17892
17893        var self = this;
17894        return function() {
17895          namedListeners[indexOf(namedListeners, listener)] = null;
17896          decrementListenerCount(self, 1, name);
17897        };
17898      },
17899
17900
17901      /**
17902       * @ngdoc method
17903       * @name $rootScope.Scope#$emit
17904       * @kind function
17905       *
17906       * @description
17907       * Dispatches an event `name` upwards through the scope hierarchy notifying the
17908       * registered {@link ng.$rootScope.Scope#$on} listeners.
17909       *
17910       * The event life cycle starts at the scope on which `$emit` was called. All
17911       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
17912       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
17913       * registered listeners along the way. The event will stop propagating if one of the listeners
17914       * cancels it.
17915       *
17916       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
17917       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
17918       *
17919       * @param {string} name Event name to emit.
17920       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
17921       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
17922       */
17923      $emit: function(name, args) {
17924        var empty = [],
17925            namedListeners,
17926            scope = this,
17927            stopPropagation = false,
17928            event = {
17929              name: name,
17930              targetScope: scope,
17931              stopPropagation: function() {stopPropagation = true;},
17932              preventDefault: function() {
17933                event.defaultPrevented = true;
17934              },
17935              defaultPrevented: false
17936            },
17937            listenerArgs = concat([event], arguments, 1),
17938            i, length;
17939
17940        do {
17941          namedListeners = scope.$$listeners[name] || empty;
17942          event.currentScope = scope;
17943          for (i=0, length=namedListeners.length; i<length; i++) {
17944
17945            // if listeners were deregistered, defragment the array
17946            if (!namedListeners[i]) {
17947              namedListeners.splice(i, 1);
17948              i--;
17949              length--;
17950              continue;
17951            }
17952            try {
17953              //allow all listeners attached to the current scope to run
17954              namedListeners[i].apply(null, listenerArgs);
17955            } catch (e) {
17956              $exceptionHandler(e);
17957            }
17958          }
17959          //if any listener on the current scope stops propagation, prevent bubbling
17960          if (stopPropagation) return event;
17961          //traverse upwards
17962          scope = scope.$parent;
17963        } while (scope);
17964
17965        return event;
17966      },
17967
17968
17969      /**
17970       * @ngdoc method
17971       * @name $rootScope.Scope#$broadcast
17972       * @kind function
17973       *
17974       * @description
17975       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
17976       * registered {@link ng.$rootScope.Scope#$on} listeners.
17977       *
17978       * The event life cycle starts at the scope on which `$broadcast` was called. All
17979       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
17980       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
17981       * scope and calls all registered listeners along the way. The event cannot be canceled.
17982       *
17983       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
17984       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
17985       *
17986       * @param {string} name Event name to broadcast.
17987       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
17988       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
17989       */
17990      $broadcast: function(name, args) {
17991        var target = this,
17992            current = target,
17993            next = target,
17994            event = {
17995              name: name,
17996              targetScope: target,
17997              preventDefault: function() {
17998                event.defaultPrevented = true;
17999              },
18000              defaultPrevented: false
18001            },
18002            listenerArgs = concat([event], arguments, 1),
18003            listeners, i, length;
18004
18005        //down while you can, then up and next sibling or up and next sibling until back at root
18006        while ((current = next)) {
18007          event.currentScope = current;
18008          listeners = current.$$listeners[name] || [];
18009          for (i=0, length = listeners.length; i<length; i++) {
18010            // if listeners were deregistered, defragment the array
18011            if (!listeners[i]) {
18012              listeners.splice(i, 1);
18013              i--;
18014              length--;
18015              continue;
18016            }
18017
18018            try {
18019              listeners[i].apply(null, listenerArgs);
18020            } catch(e) {
18021              $exceptionHandler(e);
18022            }
18023          }
18024
18025          // Insanity Warning: scope depth-first traversal
18026          // yes, this code is a bit crazy, but it works and we have tests to prove it!
18027          // this piece should be kept in sync with the traversal in $digest
18028          // (though it differs due to having the extra check for $$listenerCount)
18029          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
18030              (current !== target && current.$$nextSibling)))) {
18031            while(current !== target && !(next = current.$$nextSibling)) {
18032              current = current.$parent;
18033            }
18034          }
18035        }
18036
18037        return event;
18038      }
18039    };
18040
18041    var $rootScope = new Scope();
18042
18043    return $rootScope;
18044
18045
18046    function beginPhase(phase) {
18047      if ($rootScope.$$phase) {
18048        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
18049      }
18050
18051      $rootScope.$$phase = phase;
18052    }
18053
18054    function clearPhase() {
18055      $rootScope.$$phase = null;
18056    }
18057
18058    function compileToFn(exp, name) {
18059      var fn = $parse(exp);
18060      assertArgFn(fn, name);
18061      return fn;
18062    }
18063
18064    function decrementListenerCount(current, count, name) {
18065      do {
18066        current.$$listenerCount[name] -= count;
18067
18068        if (current.$$listenerCount[name] === 0) {
18069          delete current.$$listenerCount[name];
18070        }
18071      } while ((current = current.$parent));
18072    }
18073
18074    /**
18075     * function used as an initial value for watchers.
18076     * because it's unique we can easily tell it apart from other values
18077     */
18078    function initWatchVal() {}
18079  }];
18080}
18081
18082/**
18083 * @description
18084 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
18085 */
18086function $$SanitizeUriProvider() {
18087  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
18088    imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file):|data:image\/)/;
18089
18090  /**
18091   * @description
18092   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
18093   * urls during a[href] sanitization.
18094   *
18095   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
18096   *
18097   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
18098   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
18099   * regular expression. If a match is found, the original url is 
18099written into the dom. Otherwise,
18100   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
18101   *
18102   * @param {RegExp=} regexp New regexp to whitelist urls with.
18103   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
18104   *    chaining otherwise.
18105   */
18106  this.aHrefSanitizationWhitelist = function(regexp) {
18107    if (isDefined(regexp)) {
18108      aHrefSanitizationWhitelist = regexp;
18109      return this;
18110    }
18111    return aHrefSanitizationWhitelist;
18112  };
18113
18114
18115  /**
18116   * @description
18117   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
18118   * urls during img[src] sanitization.
18119   *
18120   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
18121   *
18122   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
18123   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
18124   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
18125   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
18126   *
18127   * @param {RegExp=} regexp New regexp to whitelist urls with.
18128   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
18129   *    chaining otherwise.
18130   */
18131  this.imgSrcSanitizationWhitelist = function(regexp) {
18132    if (isDefined(regexp)) {
18133      imgSrcSanitizationWhitelist = regexp;
18134      return this;
18135    }
18136    return imgSrcSanitizationWhitelist;
18137  };
18138
18139  this.$get = function() {
18140    return function sanitizeUri(uri, isImage) {
18141      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
18142      var normalizedVal;
18143      // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
18144      if (!msie || msie >= 8 ) {
18145        normalizedVal = urlResolve(uri).href;
18146        if (normalizedVal !== '' && !normalizedVal.match(regex)) {
18147          return 'unsafe:'+normalizedVal;
18148        }
18149      }
18150      return uri;
18151    };
18152  };
18153}
18154
18155var $sceMinErr = minErr('$sce');
18156
18157var SCE_CONTEXTS = {
18158  HTML: 'html',
18159  CSS: 'css',
18160  URL: 'url',
18161  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
18162  // url.  (e.g. ng-include, script src, templateUrl)
18163  RESOURCE_URL: 'resourceUrl',
18164  JS: 'js'
18165};
18166
18167// Helper functions follow.
18168
18169// Copied from:
18170// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
18171// Prereq: s is a string.
18172function escapeForRegexp(s) {
18173  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
18174           replace(/\x08/g, '\\x08');
18175}
18176
18177
18178function adjustMatcher(matcher) {
18179  if (matcher === 'self') {
18180    return matcher;
18181  } else if (isString(matcher)) {
18182    // Strings match exactly except for 2 wildcards - '*' and '**'.
18183    // '*' matches any character except those from the set ':/.?&'.
18184    // '**' matches any character (like .* in a RegExp).
18185    // More than 2 *'s raises an error as it's ill defined.
18186    if (matcher.indexOf('***') > -1) {
18187      throw $sceMinErr('iwcard',
18188          'Illegal sequence *** in string matcher.  String: {0}', matcher);
18189    }
18190    matcher = escapeForRegexp(matcher).
18191                  replace('\\*\\*', '.*').
18192                  replace('\\*', '[^:/.?&;]*');
18193    return new RegExp('^' + matcher + '$');
18194  } else if (isRegExp(matcher)) {
18195    // The only other type of matcher allowed is a Regexp.
18196    // Match entire URL / disallow partial matches.
18197    // Flags are reset (i.e. no global, ignoreCase or multiline)
18198    return new RegExp('^' + matcher.source + '$');
18199  } else {
18200    throw $sceMinErr('imatcher',
18201        'Matchers may only be "self", string patterns or RegExp objects');
18202  }
18203}
18204
18205
18206function adjustMatchers(matchers) {
18207  var adjustedMatchers = [];
18208  if (isDefined(matchers)) {
18209    forEach(matchers, function(matcher) {
18210      adjustedMatchers.push(adjustMatcher(matcher));
18211    });
18212  }
18213  return adjustedMatchers;
18214}
18215
18216
18217/**
18218 * @ngdoc service
18219 * @name $sceDelegate
18220 * @kind function
18221 *
18222 * @description
18223 *
18224 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
18225 * Contextual Escaping (SCE)} services to AngularJS.
18226 *
18227 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
18228 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
18229 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
18230 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
18231 * work because `$sce` delegates to `$sceDelegate` for these operations.
18232 *
18233 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
18234 *
18235 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
18236 * can override it completely to change the behavior of `$sce`, the common case would
18237 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
18238 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
18239 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
18240 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
18241 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
18242 */
18243
18244/**
18245 * @ngdoc provider
18246 * @name $sceDelegateProvider
18247 * @description
18248 *
18249 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
18250 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
18251 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
18252 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
18253 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
18254 *
18255 * For the general details about this service in Angular, read the main page for {@link ng.$sce
18256 * Strict Contextual Escaping (SCE)}.
18257 *
18258 * **Example**:  Consider the following case. <a name="example"></a>
18259 *
18260 * - your app is hosted at url `http://myapp.example.com/`
18261 * - but some of your templates are hosted on other domains you control such as
18262 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
18263 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
18264 *
18265 * Here is what a secure configuration for this scenario might look like:
18266 *
18267 * ```
18268 *  angular.module('myApp', []).config(function($sceDelegateProvider) {
18269 *    $sceDelegateProvider.resourceUrlWhitelist([
18270 *      // Allow same origin resource loads.
18271 *      'self',
18272 *      // Allow loading from our assets domain.  Notice the difference between * and **.
18273 *      'http://srv*.assets.example.com/**'
18274 *    ]);
18275 *
18276 *    // The blacklist overrides the whitelist so the open redirect here is blocked.
18277 *    $sceDelegateProvider.resourceUrlBlacklist([
18278 *      'http://myapp.example.com/clickThru**'
18279 *    ]);
18280 *  });
18281 * ```
18282 */
18283
18284function $SceDelegateProvider() {
18285  this.SCE_CONTEXTS = SCE_CONTEXTS;
18286
18287  // Resource URLs can also be trusted by policy.
18288  var resourceUrlWhitelist = ['self'],
18289      resourceUrlBlacklist = [];
18290
18291  /**
18292   * @ngdoc method
18293   * @name $sceDelegateProvider#resourceUrlWhitelist
18294   * @kind function
18295   *
18296   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
18297   *     provided.  This must be an array or null.  A snapshot of this array is used so further
18298   *     changes to the array are ignored.
18299   *
18300   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
18301   *     allowed in this array.
18302   *
18303   *     Note: **an empty whitelist array will block all URLs**!
18304   *
18305   * @return {Array} the currently set whitelist array.
18306   *
18307   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
18308   * same origin resource requests.
18309   *
18310   * @description
18311   * Sets/Gets the whitelist of trusted resource URLs.
18312   */
18313  this.resourceUrlWhitelist = function (value) {
18314    if (arguments.length) {
18315      resourceUrlWhitelist = adjustMatchers(value);
18316    }
18317    return resourceUrlWhitelist;
18318  };
18319
18320  /**
18321   * @ngdoc method
18322   * @name $sceDelegateProvider#resourceUrlBlacklist
18323   * @kind function
18324   *
18325   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
18326   *     provided.  This must be an array or null.  A snapshot of this array is used so further
18327   *     changes to the array are ignored.
18328   *
18329   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
18330   *     allowed in this array.
18331   *
18332   *     The typical usage for the blacklist is to **block
18333   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
18334   *     these would otherwise be trusted but actually return content from the redirected domain.
18335   *
18336   *     Finally, **the blacklist overrides the whitelist** and has the final say.
18337   *
18338   * @return {Array} the currently set blacklist array.
18339   *
18340   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
18341   * is no blacklist.)
18342   *
18343   * @description
18344   * Sets/Gets the blacklist of trusted resource URLs.
18345   */
18346
18347  this.resourceUrlBlacklist = function (value) {
18348    if (arguments.length) {
18349      resourceUrlBlacklist = adjustMatchers(value);
18350    }
18351    return resourceUrlBlacklist;
18352  };
18353
18354  this.$get = ['$injector', function($injector) {
18355
18356    var htmlSanitizer = function htmlSanitizer(html) {
18357      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
18358    };
18359
18360    if ($injector.has('$sanitize')) {
18361      htmlSanitizer = $injector.get('$sanitize');
18362    }
18363
18364
18365    function matchUrl(matcher, parsedUrl) {
18366      if (matcher === 'self') {
18367        return urlIsSameOrigin(parsedUrl);
18368      } else {
18369        // definitely a regex.  See adjustMatchers()
18370        return !!matcher.exec(parsedUrl.href);
18371      }
18372    }
18373
18374    function isResourceUrlAllowedByPolicy(url) {
18375      var parsedUrl = urlResolve(url.toString());
18376      var i, n, allowed = false;
18377      // Ensure that at least one item from the whitelist allows this url.
18378      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
18379        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
18380          allowed = true;
18381          break;
18382        }
18383      }
18384      if (allowed) {
18385        // Ensure that no item from the blacklist blocked this url.
18386        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
18387          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
18388            allowed = false;
18389            break;
18390          }
18391        }
18392      }
18393      return allowed;
18394    }
18395
18396    function generateHolderType(Base) {
18397      var holderType = function TrustedValueHolderType(trustedValue) {
18398        this.$$unwrapTrustedValue = function() {
18399          return trustedValue;
18400        };
18401      };
18402      if (Base) {
18403        holderType.prototype = new Base();
18404      }
18405      holderType.prototype.valueOf = function sceValueOf() {
18406        return this.$$unwrapTrustedValue();
18407      };
18408      holderType.prototype.toString = function sceToString() {
18409        return this.$$unwrapTrustedValue().toString();
18410      };
18411      return holderType;
18412    }
18413
18414    var trustedValueHolderBase = generateHolderType(),
18415        byType = {};
18416
18417    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
18418    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
18419    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
18420    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
18421    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
18422
18423    /**
18424     * @ngdoc method
18425     * @name $sceDelegate#trustAs
18426     *
18427     * @description
18428     * Returns an object that is trusted by angular for use in specified strict
18429     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
18430     * attribute interpolation, any dom event binding attribute interpolation
18431     * such as for onclick,  etc.) that uses the provided value.
18432     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
18433     *
18434     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
18435     *   resourceUrl, html, js and css.
18436     * @param {*} value The value that that should be considered trusted/safe.
18437     * @returns {*} A value that can be used to stand in for the provided `value` in places
18438     * where Angular expects a $sce.trustAs() return value.
18439     */
18440    function trustAs(type, trustedValue) {
18441      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
18442      if (!Constructor) {
18443        throw $sceMinErr('icontext',
18444            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
18445            type, trustedValue);
18446      }
18447      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
18448        return trustedValue;
18449      }
18450      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
18451      // mutable objects, we ensure here that the value passed in is actually a string.
18452      if (typeof trustedValue !== 'string') {
18453        throw $sceMinErr('itype',
18454            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
18455            type);
18456      }
18457      return new Constructor(trustedValue);
18458    }
18459
18460    /**
18461     * @ngdoc method
18462     * @name $sceDelegate#valueOf
18463     *
18464     * @description
18465     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
18466     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
18467     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
18468     *
18469     * If the passed parameter is not a value that had been returned by {@link
18470     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
18471     *
18472     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
18473     *      call or anything else.
18474     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
18475     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
18476     *     `value` unchanged.
18477     */
18478    function valueOf(maybeTrusted) {
18479      if (maybeTrusted instanceof trustedValueHolderBase) {
18480        return maybeTrusted.$$unwrapTrustedValue();
18481      } else {
18482        return maybeTrusted;
18483      }
18484    }
18485
18486    /**
18487     * @ngdoc method
18488     * @name $sceDelegate#getTrusted
18489     *
18490     * @description
18491     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
18492     * returns the originally supplied value if the queried context type is a supertype of the
18493     * created type.  If this condition isn't satisfied, throws an exception.
18494     *
18495     * @param {string} type The kind of context in which this value is to be used.
18496     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
18497     *     `$sceDelegate.trustAs`} call.
18498     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
18499     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
18500     */
18501    function getTrusted(type, maybeTrusted) {
18502      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
18503        return maybeTrusted;
18504      }
18505      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
18506      if (constructor && maybeTrusted instanceof constructor) {
18507        return maybeTrusted.$$unwrapTrustedValue();
18508      }
18509      // If we get here, then we may only take one of two actions.
18510      // 1. sanitize the value for the requested type, or
18511      // 2. throw an exception.
18512      if (type === SCE_CONTEXTS.RESOURCE_URL) {
18513        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
18514          return maybeTrusted;
18515        } else {
18516          throw $sceMinErr('insecurl',
18517              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
18518              maybeTrusted.toString());
18519        }
18520      } else if (type === SCE_CONTEXTS.HTML) {
18521        return htmlSanitizer(maybeTrusted);
18522      }
18523      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
18524    }
18525
18526    return { trustAs: trustAs,
18527             getTrusted: getTrusted,
18528             valueOf: valueOf };
18529  }];
18530}
18531
18532
18533/**
18534 * @ngdoc provider
18535 * @name $sceProvider
18536 * @description
18537 *
18538 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
18539 * -   enable/disable Strict Contextual Escaping (SCE) in a module
18540 * -   override the default implementation with a custom delegate
18541 *
18542 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
18543 */
18544
18545/* jshint maxlen: false*/
18546
18547/**
18548 * @ngdoc service
18549 * @name $sce
18550 * @kind function
18551 *
18552 * @description
18553 *
18554 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
18555 *
18556 * # Strict Contextual Escaping
18557 *
18558 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
18559 * contexts to result in a value that is marked as safe to use for that context.  One example of
18560 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
18561 * to these contexts as privileged or SCE contexts.
18562 *
18563 * As of version 1.2, Angular ships with SCE enabled by default.
18564 *
18565 * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
18566 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
18567 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
18568 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
18569 * to the top of your HTML document.
18570 *
18571 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
18572 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
18573 *
18574 * Here's an example of a binding in a privileged context:
18575 *
18576 * ```
18577 * <input ng-model="userHtml">
18578 * <div ng-bind-html="userHtml"></div>
18579 * ```
18580 *
18581 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
18582 * disabled, this application allows the user to render arbitrary HTML into the DIV.
18583 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
18584 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
18585 * security vulnerabilities.)
18586 *
18587 * For the case of HTML, you might use a library, either on the client side, or on the server side,
18588 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
18589 *
18590 * How would you ensure that every place that used these types of bindings was bound to a value that
18591 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
18592 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
18593 * properties/fields and forgot to update the binding to the sanitized value?
18594 *
18595 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
18596 * determine that something explicitly says it's safe to use a value for binding in that
18597 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
18598 * for those values that you can easily tell are safe - because they were received from your server,
18599 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
18600 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
18601 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
18602 *
18603 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
18604 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
18605 * obtain values that will be accepted by SCE / privileged contexts.
18606 *
18607 *
18608 * ## How does it work?
18609 *
18610 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
18611 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
18612 * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
18613 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
18614 *
18615 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
18616 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
18617 * simplified):
18618 *
18619 * ```
18620 * var ngBindHtmlDirective = ['$sce', function($sce) {
18621 *   return function(scope, element, attr) {
18622 *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
18623 *       element.html(value || '');
18624 *     });
18625 *   };
18626 * }];
18627 * ```
18628 *
18629 * ## Impact on loading templates
18630 *
18631 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
18632 * `templateUrl`'s specified by {@link guide/directive directives}.
18633 *
18634 * By default, Angular only loads templates from the same domain and protocol as the application
18635 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
18636 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
18637 * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
18638 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
18639 *
18640 * *Please note*:
18641 * The browser's
18642 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
18643 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
18644 * policy apply in addition to this and may further restrict whether the template is successfully
18645 * loaded.  This means that without the right CORS policy, loading templates from a different domain
18646 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
18647 * browsers.
18648 *
18649 * ## This feels like too much overhead for the developer?
18650 *
18651 * It's important to remember that SCE only applies to interpolation expressions.
18652 *
18653 * If your expressions are constant literals, they're automatically trusted and you don't need to
18654 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
18655 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
18656 *
18657 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
18658 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
18659 *
18660 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
18661 * templates in `ng-include` from your application's domain without having to even know about SCE.
18662 * It blocks loading templates from other domains or loading templates over http from an https
18663 * served document.  You can change these by setting your own custom {@link
18664 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
18665 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
18666 *
18667 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
18668 * application that's secure and can be audited to verify that with much more ease than bolting
18669 * security onto an application later.
18670 *
18671 * <a name="contexts"></a>
18672 * ## What trusted context types are supported?
18673 *
18674 * | Context             | Notes          |
18675 * |---------------------|----------------|
18676 * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. |
18677 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
18678 * | `$sce.URL`          | For URLs that are safe to follow as links.  Currently unused (`<a href=` and `<img src=` sanitize their urls and don't constitute an SCE context. |
18679 * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application.  Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.)  <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
18680 * | `$sce.JS`           | For JavaScript that is safe to execute in your application's context.  Currently unused.  Feel free to use it in your own directives. |
18681 *
18682 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
18683 *
18684 *  Each element in these arrays must be one of the following:
18685 *
18686 *  - **'self'**
18687 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
18688 *      domain** as the application document using the **same protocol**.
18689 *  - **String** (except the special value `'self'`)
18690 *    - The string is matched against the full *normalized / absolute URL* of the resource
18691 *      being tested (substring matches are not good enough.)
18692 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
18693 *      match themselves.
18694 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
18695 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
18696 *      in a whitelist.
18697 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
18698 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
18699 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
18700 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
18701 *      http://foo.example.com/templates/**).
18702 *  - **RegExp** (*see caveat below*)
18703 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
18704 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
18705 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
18706 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
18707 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
18708 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
18709 *      is highly recommended to use the string patterns and only fall back to regular expressions
18710 *      if they as a last resort.
18711 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
18712 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
18713 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
18714 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
18715 *    - If you are generating your JavaScript from some other templating engine (not
18716 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
18717 *      remember to escape your regular expression (and be aware that you might need more than
18718 *      one level of escaping depending on your templating engine and the way you interpolated
18719 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
18720 *      enough before coding your own.  e.g. Ruby has
18721 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
18722 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
18723 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
18724 *      Closure library's [goog.string.regExpEscape(s)](
18725 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
18726 *
18727 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
18728 *
18729 * ## Show me an example using SCE.
18730 *
18731 * <example module="mySceApp" deps="angular-sanitize.js">
18732 * <file name="index.html">
18733 *   <div ng-controller="myAppController as myCtrl">
18734 *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
18735 *     <b>User comments</b><br>
18736 *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
18737 *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
18738 *     exploit.
18739 *     <div class="well">
18740 *       <div ng-repeat="userComment in myCtrl.userComments">
18741 *         <b>{{userComment.name}}</b>:
18742 *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
18743 *         <br>
18744 *       </div>
18745 *     </div>
18746 *   </div>
18747 * </file>
18748 *
18749 * <file name="script.js">
18750 *   var mySceApp = angular.module('mySceApp', ['ngSanitize']);
18751 *
18752 *   mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
18753 *     var self = this;
18754 *     $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
18755 *       self.userComments = userComments;
18756 *     });
18757 *     self.explicitlyTrustedHtml = $sce.trustAsHtml(
18758 *         '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
18759 *         'sanitization.&quot;">Hover over this text.</span>');
18760 *   });
18761 * </file>
18762 *
18763 * <file name="test_data.json">
18764 * [
18765 *   { "name": "Alice",
18766 *     "htmlComment":
18767 *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
18768 *   },
18769 *   { "name": "Bob",
18770 *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
18771 *   }
18772 * ]
18773 * </file>
18774 *
18775 * <file name="protractor.js" type="protractor">
18776 *   describe('SCE doc demo', function() {
18777 *     it('should sanitize untrusted values', function() {
18778 *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
18779 *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
18780 *     });
18781 *
18782 *     it('should NOT sanitize explicitly trusted values', function() {
18783 *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
18784 *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
18785 *           'sanitization.&quot;">Hover over this text.</span>');
18786 *     });
18787 *   });
18788 * </file>
18789 * </example>
18790 *
18791 *
18792 *
18793 * ## Can I disable SCE completely?
18794 *
18795 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
18796 * for little coding overhead.  It will be much harder to take an SCE disabled application and
18797 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
18798 * for cases where you have a lot of existing code that was written before SCE was introduced and
18799 * you're migrating them a module at a time.
18800 *
18801 * That said, here's how you can completely disable SCE:
18802 *
18803 * ```
18804 * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
18805 *   // Completely disable SCE.  For demonstration purposes only!
18806 *   // Do not use in new projects.
18807 *   $sceProvider.enabled(false);
18808 * });
18809 * ```
18810 *
18811 */
18812/* jshint maxlen: 100 */
18813
18814function $SceProvider() {
18815  var enabled = true;
18816
18817  /**
18818   * @ngdoc method
18819   * @name $sceProvider#enabled
18820   * @kind function
18821   *
18822   * @param {boolean=} value If provided, then enables/disables SCE.
18823   * @return {boolean} true if SCE is enabled, false otherwise.
18824   *
18825   * @description
18826   * Enables/disables SCE and returns the current value.
18827   */
18828  this.enabled = function (value) {
18829    if (arguments.length) {
18830      enabled = !!value;
18831    }
18832    return enabled;
18833  };
18834
18835
18836  /* Design notes on the default implementation for SCE.
18837   *
18838   * The API contract for the SCE delegate
18839   * -------------------------------------
18840   * The SCE delegate object must provide the following 3 methods:
18841   *
18842   * - trustAs(contextEnum, value)
18843   *     This method is used to tell the SCE service that the provided value is OK to use in the
18844   *     contexts specified by contextEnum.  It must return an object that will be accepted by
18845   *     getTrusted() for a compatible contextEnum and return this value.
18846   *
18847   * - valueOf(value)
18848   *     For values that were not produced by trustAs(), return them as is.  For values that were
18849   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
18850   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
18851   *     such a value.
18852   *
18853   * - getTrusted(contextEnum, value)
18854   *     This function should return the a value that is safe to use in the context specified by
18855   *     contextEnum or throw and exception otherwise.
18856   *
18857   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
18858   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
18859   * instance, an implementation could maintain a registry of all trusted objects by context.  In
18860   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
18861   * return the same object passed in if it was found in the registry under a compatible context or
18862   * throw an exception otherwise.  An implementation might only wrap values some of the time based
18863   * on some criteria.  getTrusted() might return a value and not throw an exception for special
18864   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
18865   *
18866   *
18867   * A note on the inheritance model for SCE contexts
18868   * ------------------------------------------------
18869   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
18870   * is purely an implementation details.
18871   *
18872   * The contract is simply this:
18873   *
18874   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
18875   *     will also succeed.
18876   *
18877   * Inheritance happens to capture this in a natural way.  In some future, we
18878   * may not use inheritance anymore.  That is OK because no code outside of
18879   * sce.js and sceSpecs.js would need to be aware of this detail.
18880   */
18881
18882  this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
18883                $parse,   $sniffer,   $sceDelegate) {
18884    // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
18885    // the "expression(javascript expression)" syntax which is insecure.
18886    if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
18887      throw $sceMinErr('iequirks',
18888        'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
18889        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
18890        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
18891    }
18892
18893    var sce = shallowCopy(SCE_CONTEXTS);
18894
18895    /**
18896     * @ngdoc method
18897     * @name $sce#isEnabled
18898     * @kind function
18899     *
18900     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
18901     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
18902     *
18903     * @description
18904     * Returns a boolean indicating if SCE is enabled.
18905     */
18906    sce.isEnabled = function () {
18907      return enabled;
18908    };
18909    sce.trustAs = $sceDelegate.trustAs;
18910    sce.getTrusted = $sceDelegate.getTrusted;
18911    sce.valueOf = $sceDelegate.valueOf;
18912
18913    if (!enabled) {
18914      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
18915      sce.valueOf = identity;
18916    }
18917
18918    /**
18919     * @ngdoc method
18920     * @name $sce#parseAs
18921     *
18922     * @description
18923     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
18924     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
18925     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
18926     * *result*)}
18927     *
18928     * @param {string} type The kind of SCE context in which this result will be used.
18929     * @param {string} expression String expression to compile.
18930     * @returns {function(context, locals)} a function which represents the compiled expression:
18931     *
18932     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
18933     *      are evaluated against (typically a scope object).
18934     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
18935     *      `context`.
18936     */
18937    sce.parseAs = function sceParseAs(type, expr) {
18938      var parsed = $parse(expr);
18939      if (parsed.literal && parsed.constant) {
18940        return parsed;
18941      } else {
18942        return function sceParseAsTrusted(self, locals) {
18943          return sce.getTrusted(type, parsed(self, locals));
18944        };
18945      }
18946    };
18947
18948    /**
18949     * @ngdoc method
18950     * @name $sce#trustAs
18951     *
18952     * @description
18953     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
18954     * returns an object that is trusted by angular for use in specified strict contextual
18955     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
18956     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
18957     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
18958     * escaping.
18959     *
18960     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
18961     *   resource_url, html, js and css.
18962     * @param {*} value The value that that should be considered trusted/safe.
18963     * @returns {*} A value that can be used to stand in for the provided `value` in places
18964     * where Angular expects a $sce.trustAs() return value.
18965     */
18966
18967    /**
18968     * @ngdoc method
18969     * @name $sce#trustAsHtml
18970     *
18971     * @description
18972     * Shorthand method.  `$sce.trustAsHtml(value)` →
18973     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
18974     *
18975     * @param {*} value The value to trustAs.
18976     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
18977     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
18978     *     only accept expressions that are either literal constants or are the
18979     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
18980     */
18981
18982    /**
18983     * @ngdoc method
18984     * @name $sce#trustAsUrl
18985     *
18986     * @description
18987     * Shorthand method.  `$sce.trustAsUrl(value)` →
18988     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
18989     *
18990     * @param {*} value The value to trustAs.
18991     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
18992     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
18993     *     only accept expressions that are either literal constants or are the
18994     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
18995     */
18996
18997    /**
18998     * @ngdoc method
18999     * @name $sce#trustAsResourceUrl
19000     *
19001     * @description
19002     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
19003     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
19004     *
19005     * @param {*} value The value to trustAs.
19006     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
19007     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
19008     *     only accept expressions that are either literal constants or are the return
19009     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
19010     */
19011
19012    /**
19013     * @ngdoc method
19014     * @name $sce#trustAsJs
19015     *
19016     * @description
19017     * Shorthand method.  `$sce.trustAsJs(value)` →
19018     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
19019     *
19020     * @param {*} value The value to trustAs.
19021     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
19022     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
19023     *     only accept expressions that are either literal constants or are the
19024     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
19025     */
19026
19027    /**
19028     * @ngdoc method
19029     * @name $sce#getTrusted
19030     *
19031     * @description
19032     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
19033     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
19034     * originally supplied value if the queried context type is a supertype of the created type.
19035     * If this condition isn't satisfied, throws an exception.
19036     *
19037     * @param {string} type The kind of context in which this value is to be used.
19038     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
19039     *                         call.
19040     * @returns {*} The value the was originally provided to
19041     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
19042     *              Otherwise, throws an exception.
19043     */
19044
19045    /**
19046     * @ngdoc method
19047     * @name $sce#getTrustedHtml
19048     *
19049     * @description
19050     * Shorthand method.  `$sce.getTrustedHtml(value)` →
19051     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
19052     *
19053     * @param {*} value The value to pass to `$sce.getTrusted`.
19054     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
19055     */
19056
19057    /**
19058     * @ngdoc method
19059     * @name $sce#getTrustedCss
19060     *
19061     * @description
19062     * Shorthand method.  `$sce.getTrustedCss(value)` →
19063     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
19064     *
19065     * @param {*} value The value to pass to `$sce.getTrusted`.
19066     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
19067     */
19068
19069    /**
19070     * @ngdoc method
19071     * @name $sce#getTrustedUrl
19072     *
19073     * @description
19074     * Shorthand method.  `$sce.getTrustedUrl(value)` →
19075     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
19076     *
19077     * @param {*} value The value to pass to `$sce.getTrusted`.
19078     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
19079     */
19080
19081    /**
19082     * @ngdoc method
19083     * @name $sce#getTrustedResourceUrl
19084     *
19085     * @description
19086     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
19087     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
19088     *
19089     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
19090     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
19091     */
19092
19093    /**
19094     * @ngdoc method
19095     * @name $sce#getTrustedJs
19096     *
19097     * @description
19098     * Shorthand method.  `$sce.getTrustedJs(value)` →
19099     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
19100     *
19101     * @param {*} value The value to pass to `$sce.getTrusted`.
19102     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
19103     */
19104
19105    /**
19106     * @ngdoc method
19107     * @name $sce#parseAsHtml
19108     *
19109     * @description
19110     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
19111     *     {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
19112     *
19113     * @param {string} expression String expression to compile.
19114     * @returns {function(context, locals)} a function which represents the compiled expression:
19115     *
19116     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
19117     *      are evaluated against (typically a scope object).
19118     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
19119     *      `context`.
19120     */
19121
19122    /**
19123     * @ngdoc method
19124     * @name $sce#parseAsCss
19125     *
19126     * @description
19127     * Shorthand method.  `$sce.parseAsCss(value)` →
19128     *     {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
19129     *
19130     * @param {string} expression String expression to compile.
19131     * @returns {function(context, locals)} a function which represents the compiled expression:
19132     *
19133     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
19134     *      are evaluated against (typically a scope object).
19135     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
19136     *      `context`.
19137     */
19138
19139    /**
19140     * @ngdoc method
19141     * @name $sce#parseAsUrl
19142     *
19143     * @description
19144     * Shorthand method.  `$sce.parseAsUrl(value)` →
19145     *     {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
19146     *
19147     * @param {string} expression String expression to compile.
19148     * @returns {function(context, locals)} a function which represents the compiled expression:
19149     *
19150     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
19151     *      are evaluated against (typically a scope object).
19152     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
19153     *      `context`.
19154     */
19155
19156    /**
19157     * @ngdoc method
19158     * @name $sce#parseAsResourceUrl
19159     *
19160     * @description
19161     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
19162     *     {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
19163     *
19164     * @param {string} expression String expression to compile.
19165     * @returns {function(context, locals)} a function which represents the compiled expression:
19166     *
19167     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
19168     *      are evaluated against (typically a scope object).
19169     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
19170     *      `context`.
19171     */
19172
19173    /**
19174     * @ngdoc method
19175     * @name $sce#parseAsJs
19176     *
19177     * @description
19178     * Shorthand method.  `$sce.parseAsJs(value)` →
19179     *     {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
19180     *
19181     * @param {string} expression String expression to compile.
19182     * @returns {function(context, locals)} a function which represents the compiled expression:
19183     *
19184     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
19185     *      are evaluated against (typically a scope object).
19186     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
19187     *      `context`.
19188     */
19189
19190    // Shorthand delegations.
19191    var parse = sce.parseAs,
19192        getTrusted = sce.getTrusted,
19193        trustAs = sce.trustAs;
19194
19195    forEach(SCE_CONTEXTS, function (enumValue, name) {
19196      var lName = lowercase(name);
19197      sce[camelCase("parse_as_" + lName)] = function (expr) {
19198        return parse(enumValue, expr);
19199      };
19200      sce[camelCase("get_trusted_" + lName)] = function (value) {
19201        return getTrusted(enumValue, value);
19202      };
19203      sce[camelCase("trust_as_" + lName)] = function (value) {
19204        return trustAs(enumValue, value);
19205      };
19206    });
19207
19208    return sce;
19209  }];
19210}
19211
19212/**
19213 * !!! This is an undocumented "private" service !!!
19214 *
19215 * @name $sniffer
19216 * @requires $window
19217 * @requires $document
19218 *
19219 * @property {boolean} history Does the browser support html5 history api ?
19220 * @property {boolean} hashchange Does the browser support hashchange event ?
19221 * @property {boolean} transitions Does the browser support CSS transition events ?
19222 * @property {boolean} animations Does the browser support CSS animation events ?
19223 *
19224 * @description
19225 * This is very simple implementation of testing browser's features.
19226 */
19227function $SnifferProvider() {
19228  this.$get = ['$window', '$document', function($window, $document) {
19229    var eventSupport = {},
19230        android =
19231          int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
19232        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
19233        document = $document[0] || {},
19234        documentMode = document.documentMode,
19235        vendorPrefix,
19236        vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
19237        bodyStyle = document.body && document.body.style,
19238        transitions = false,
19239        animations = false,
19240        match;
19241
19242    if (bodyStyle) {
19243      for(var prop in bodyStyle) {
19244        if(match = vendorRegex.exec(prop)) {
19245          vendorPrefix = match[0];
19246          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
19247          break;
19248        }
19249      }
19250
19251      if(!vendorPrefix) {
19252        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
19253      }
19254
19255      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
19256      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
19257
19258      if (android && (!transitions||!animations)) {
19259        transitions = isString(document.body.style.webkitTransition);
19260        animations = isString(document.body.style.webkitAnimation);
19261      }
19262    }
19263
19264
19265    return {
19266      // Android has history.pushState, but it does not update location correctly
19267      // so let's not use the history API at all.
19268      // http://code.google.com/p/android/issues/detail?id=17471
19269      // https://github.com/angular/angular.js/issues/904
19270
19271      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
19272      // so let's not use the history API also
19273      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
19274      // jshint -W018
19275      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
19276      // jshint +W018
19277      hashchange: 'onhashchange' in $window &&
19278                  // IE8 compatible mode lies
19279                  (!documentMode || documentMode > 7),
19280      hasEvent: function(event) {
19281        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
19282        // it. In particular the event is not fired when backspace or delete key are pressed or
19283        // when cut operation is performed.
19284        if (event == 'input' && msie == 9) return false;
19285
19286        if (isUndefined(eventSupport[event])) {
19287          var divElm = document.createElement('div');
19288          eventSupport[event] = 'on' + event in divElm;
19289        }
19290
19291        return eventSupport[event];
19292      },
19293      csp: csp(),
19294      vendorPrefix: vendorPrefix,
19295      transitions : transitions,
19296      animations : animations,
19297      android: android,
19298      msie : msie,
19299      msieDocumentMode: documentMode
19300    };
19301  }];
19302}
19303
19304function $TimeoutProvider() {
19305  this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
19306       function($rootScope,   $browser,   $q,   $exceptionHandler) {
19307    var deferreds = {};
19308
19309
19310     /**
19311      * @ngdoc service
19312      * @name $timeout
19313      *
19314      * @description
19315      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
19316      * block and delegates any exceptions to
19317      * {@link ng.$exceptionHandler $exceptionHandler} service.
19318      *
19319      * The return value of registering a timeout function is a promise, which will be resolved when
19320      * the timeout is reached and the timeout function is executed.
19321      *
19322      * To cancel a timeout request, call `$timeout.cancel(promise)`.
19323      *
19324      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
19325      * synchronously flush the queue of deferred functions.
19326      *
19327      * @param {function()} fn A function, whose execution should be delayed.
19328      * @param {number=} [delay=0] Delay in milliseconds.
19329      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
19330      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
19331      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
19332      *   promise will be resolved with is the return value of the `fn` function.
19333      *
19334      */
19335    function timeout(fn, delay, invokeApply) {
19336      var deferred = $q.defer(),
19337          promise = deferred.promise,
19338          skipApply = (isDefined(invokeApply) && !invokeApply),
19339          timeoutId;
19340
19341      timeoutId = $browser.defer(function() {
19342        try {
19343          deferred.resolve(fn());
19344        } catch(e) {
19345          deferred.reject(e);
19346          $exceptionHandler(e);
19347        }
19348        finally {
19349          delete deferreds[promise.$$timeoutId];
19350        }
19351
19352        if (!skipApply) $rootScope.$apply();
19353      }, delay);
19354
19355      promise.$$timeoutId = timeoutId;
19356      deferreds[timeoutId] = deferred;
19357
19358      return promise;
19359    }
19360
19361
19362     /**
19363      * @ngdoc method
19364      * @name $timeout#cancel
19365      *
19366      * @description
19367      * Cancels a task associated with the `promise`. As a result of this, the promise will be
19368      * resolved with a rejection.
19369      *
19370      * @param {Promise=} promise Promise returned by the `$timeout` function.
19371      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
19372      *   canceled.
19373      */
19374    timeout.cancel = function(promise) {
19375      if (promise && promise.$$timeoutId in deferreds) {
19376        deferreds[promise.$$timeoutId].reject('canceled');
19377        delete deferreds[promise.$$timeoutId];
19378        return $browser.defer.cancel(promise.$$timeoutId);
19379      }
19380      return false;
19381    };
19382
19383    return timeout;
19384  }];
19385}
19386
19387// NOTE:  The usage of window and document instead of $window and $document here is
19388// deliberate.  This service depends on the specific behavior of anchor nodes created by the
19389// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
19390// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
19391// doesn't know about mocked locations and resolves URLs to the real document - which is
19392// exactly the behavior needed here.  There is little value is mocking these out for this
19393// service.
19394var urlParsingNode = document.createElement("a");
19395var originUrl = urlResolve(window.location.href, true);
19396
19397
19398/**
19399 *
19400 * Implementation Notes for non-IE browsers
19401 * ----------------------------------------
19402 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
19403 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
19404 * URL will be resolved into an absolute URL in the context of the application document.
19405 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
19406 * properties are all populated to reflect the normalized URL.  This approach has wide
19407 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
19408 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
19409 *
19410 * Implementation Notes for IE
19411 * ---------------------------
19412 * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
19413 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
19414 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
19415 * work around that by performing the parsing in a 2nd step by taking a previously normalized
19416 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
19417 * properties such as protocol, hostname, port, etc.
19418 *
19419 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
19420 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
19421 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
19422 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
19423 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
19424 * method and IE < 8 is unsupported.
19425 *
19426 * References:
19427 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
19428 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
19429 *   http://url.spec.whatwg.org/#urlutils
19430 *   https://github.com/angular/angular.js/pull/2902
19431 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
19432 *
19433 * @kind function
19434 * @param {string} url The URL to be parsed.
19435 * @description Normalizes and parses a URL.
19436 * @returns {object} Returns the normalized URL as a dictionary.
19437 *
19438 *   | member name   | Description    |
19439 *   |---------------|----------------|
19440 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
19441 *   | protocol      | The protocol including the trailing colon                              |
19442 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
19443 *   | search        | The search params, minus the question mark                             |
19444 *   | hash          | The hash string, minus the hash symbol
19445 *   | hostname      | The hostname
19446 *   | port          | The port, without ":"
19447 *   | pathname      | The pathname, beginning with "/"
19448 *
19449 */
19450function urlResolve(url, base) {
19451  var href = url;
19452
19453  if (msie) {
19454    // Normalize before parse.  Refer Implementation Notes on why this is
19455    // done in two steps on IE.
19456    urlParsingNode.setAttribute("href", href);
19457    href = urlParsingNode.href;
19458  }
19459
19460  urlParsingNode.setAttribute('href', href);
19461
19462  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
19463  return {
19464    href: urlParsingNode.href,
19465    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
19466    host: urlParsingNode.host,
19467    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
19468    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
19469    hostname: urlParsingNode.hostname,
19470    port: urlParsingNode.port,
19471    pathname: (urlParsingNode.pathname.charAt(0) === '/')
19472      ? urlParsingNode.pathname
19473      : '/' + urlParsingNode.pathname
19474  };
19475}
19476
19477/**
19478 * Parse a request URL and determine whether this is a same-origin request as the application document.
19479 *
19480 * @param {string|object} requestUrl The url of the request as a string that will be resolved
19481 * or a parsed URL object.
19482 * @returns {boolean} Whether the request is for the same origin as the application document.
19483 */
19484function urlIsSameOrigin(requestUrl) {
19485  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
19486  return (parsed.protocol === originUrl.protocol &&
19487          parsed.host === originUrl.host);
19488}
19489
19490/**
19491 * @ngdoc service
19492 * @name $window
19493 *
19494 * @description
19495 * A reference to the browser's `window` object. While `window`
19496 * is globally available in JavaScript, it causes testability problems, because
19497 * it is a global variable. In angular we always refer to it through the
19498 * `$window` service, so it may be overridden, removed or mocked for testing.
19499 *
19500 * Expressions, like the one defined for the `ngClick` directive in the example
19501 * below, are evaluated with respect to the current scope.  Therefore, there is
19502 * no risk of inadvertently coding in a dependency on a global value in such an
19503 * expression.
19504 *
19505 * @example
19506   <example module="windowExample">
19507     <file name="index.html">
19508       <script>
19509         angular.module('windowExample', [])
19510           .controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
19511             $scope.greeting = 'Hello, World!';
19512             $scope.doGreeting = function(greeting) {
19513               $window.alert(greeting);
19514             };
19515           }]);
19516       </script>
19517       <div ng-controller="ExampleController">
19518         <input type="text" ng-model="greeting" />
19519         <button ng-click="doGreeting(greeting)">ALERT</button>
19520       </div>
19521     </file>
19522     <file name="protractor.js" type="protractor">
19523      it('should display the greeting in the input box', function() {
19524       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
19525       // If we click the button it will block the test runner
19526       // element(':button').click();
19527      });
19528     </file>
19529   </example>
19530 */
19531function $WindowProvider(){
19532  this.$get = valueFn(window);
19533}
19534
19535/* global currencyFilter: true,
19536 dateFilter: true,
19537 filterFilter: true,
19538 jsonFilter: true,
19539 limitToFilter: true,
19540 lowercaseFilter: true,
19541 numberFilter: true,
19542 orderByFilter: true,
19543 uppercaseFilter: true,
19544 */
19545
19546/**
19547 * @ngdoc provider
19548 * @name $filterProvider
19549 * @description
19550 *
19551 * Filters are just functions which transform input to an output. However filters need to be
19552 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
19553 * annotated with dependencies and is responsible for creating a filter function.
19554 *
19555 * ```js
19556 *   // Filter registration
19557 *   function MyModule($provide, $filterProvider) {
19558 *     // create a service to demonstrate injection (not always needed)
19559 *     $provide.value('greet', function(name){
19560 *       return 'Hello ' + name + '!';
19561 *     });
19562 *
19563 *     // register a filter factory which uses the
19564 *     // greet service to demonstrate DI.
19565 *     $filterProvider.register('greet', function(greet){
19566 *       // return the filter function which uses the greet service
19567 *       // to generate salutation
19568 *       return function(text) {
19569 *         // filters need to be forgiving so check input validity
19570 *         return text && greet(text) || text;
19571 *       };
19572 *     });
19573 *   }
19574 * ```
19575 *
19576 * The filter function is registered with the `$injector` under the filter name suffix with
19577 * `Filter`.
19578 *
19579 * ```js
19580 *   it('should be the same instance', inject(
19581 *     function($filterProvider) {
19582 *       $filterProvider.register('reverse', function(){
19583 *         return ...;
19584 *       });
19585 *     },
19586 *     function($filter, reverseFilter) {
19587 *       expect($filter('reverse')).toBe(reverseFilter);
19588 *     });
19589 * ```
19590 *
19591 *
19592 * For more information about how angular filters work, and how to create your own filters, see
19593 * {@link guide/filter Filters} in the Angular Developer Guide.
19594 */
19595
19596/**
19597 * @ngdoc service
19598 * @name $filter
19599 * @kind function
19600 * @description
19601 * Filters are used for formatting data displayed to the user.
19602 *
19603 * The general syntax in templates is as follows:
19604 *
19605 *         {{ expression [| filter_name[:parameter_value] ... ] }}
19606 *
19607 * @param {String} name Name of the filter function to retrieve
19608 * @return {Function} the filter function
19609 * @example
19610   <example name="$filter" module="filterExample">
19611     <file name="index.html">
19612       <div ng-controller="MainCtrl">
19613        <h3>{{ originalText }}</h3>
19614        <h3>{{ filteredText }}</h3>
19615       </div>
19616     </file>
19617
19618     <file name="script.js">
19619      angular.module('filterExample', [])
19620      .controller('MainCtrl', function($scope, $filter) {
19621        $scope.originalText = 'hello';
19622        $scope.filteredText = $filter('uppercase')($scope.originalText);
19623      });
19624     </file>
19625   </example>
19626  */
19627$FilterProvider.$inject = ['$provide'];
19628function $FilterProvider($provide) {
19629  var suffix = 'Filter';
19630
19631  /**
19632   * @ngdoc method
19633   * @name $filterProvider#register
19634   * @param {string|Object} name Name of the filter function, or an object map of filters where
19635   *    the keys are the filter names and the values are the filter factories.
19636   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
19637   *    of the registered filter instances.
19638   */
19639  function register(name, factory) {
19640    if(isObject(name)) {
19641      var filters = {};
19642      forEach(name, function(filter, key) {
19643        filters[key] = register(key, filter);
19644      });
19645      return filters;
19646    } else {
19647      return $provide.factory(name + suffix, factory);
19648    }
19649  }
19650  this.register = register;
19651
19652  this.$get = ['$injector', function($injector) {
19653    return function(name) {
19654      return $injector.get(name + suffix);
19655    };
19656  }];
19657
19658  ////////////////////////////////////////
19659
19660  /* global
19661    currencyFilter: false,
19662    dateFilter: false,
19663    filterFilter: false,
19664    jsonFilter: false,
19665    limitToFilter: false,
19666    lowercaseFilter: false,
19667    numberFilter: false,
19668    orderByFilter: false,
19669    uppercaseFilter: false,
19670  */
19671
19672  register('currency', currencyFilter);
19673  register('date', dateFilter);
19674  register('filter', filterFilter);
19675  register('json', jsonFilter);
19676  register('limitTo', limitToFilter);
19677  register('lowercase', lowercaseFilter);
19678  register('number', numberFilter);
19679  register('orderBy', orderByFilter);
19680  register('uppercase', uppercaseFilter);
19681}
19682
19683/**
19684 * @ngdoc filter
19685 * @name filter
19686 * @kind function
19687 *
19688 * @description
19689 * Selects a subset of items from `array` and returns it as a new array.
19690 *
19691 * @param {Array} array The source array.
19692 * @param {string|Object|function()} expression The predicate to be used for selecting items from
19693 *   `array`.
19694 *
19695 *   Can be one of:
19696 *
19697 *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
19698 *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
19699 *     will be returned. The predicate can be negated by prefixing the string with `!`.
19700 *
19701 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
19702 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
19703 *     which have property `name` containing "M" and property `phone` containing "1". A special
19704 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
19705 *     property of the object. That's equivalent to the simple substring match with a `string`
19706 *     as described above. The predicate can be negated by prefixing the string with `!`.
19707 *     For Example `{name: "!M"}` predicate will return an array of items which have property `name`
19708 *     not containing "M".
19709 *
19710 *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
19711 *     called for each element of `array`. The final result is an array of those elements that
19712 *     the predicate returned true for.
19713 *
19714 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
19715 *     determining if the expected value (from the filter expression) and actual value (from
19716 *     the object in the array) should be considered a match.
19717 *
19718 *   Can be one of:
19719 *
19720 *   - `function(actual, expected)`:
19721 *     The function will be given the object value and the predicate value to compare and
19722 *     should return true if the item should be included in filtered result.
19723 *
19724 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
19725 *     this is essentially strict comparison of expected and actual.
19726 *
19727 *   - `false|undefined`: A short hand for a function which will look for a substring match in case
19728 *     insensitive way.
19729 *
19730 * @example
19731   <example>
19732     <file name="index.html">
19733       <div ng-init="friends = [{name:'John', phone:'555-1276'},
19734                                {name:'Mary', phone:'800-BIG-MARY'},
19735                                {name:'Mike', phone:'555-4321'},
19736                                {name:'Adam', phone:'555-5678'},
19737                                {name:'Julie', phone:'555-8765'},
19738                                {name:'Juliette', phone:'555-5678'}]"></div>
19739
19740       Search: <input ng-model="searchText">
19741       <table id="searchTextResults">
19742         <tr><th>Name</th><th>Phone</th></tr>
19743         <tr ng-repeat="friend in friends | filter:searchText">
19744           <td>{{friend.name}}</td>
19745           <td>{{friend.phone}}</td>
19746         </tr>
19747       </table>
19748       <hr>
19749       Any: <input ng-model="search.$"> <br>
19750       Name only <input ng-model="search.name"><br>
19751       Phone only <input ng-model="search.phone"><br>
19752       Equality <input type="checkbox" ng-model="strict"><br>
19753       <table id="searchObjResults">
19754         <tr><th>
19754Name</th><th>Phone</th></tr>
19755         <tr ng-repeat="friendObj in friends | filter:search:strict">
19756           <td>{{friendObj.name}}</td>
19757           <td>{{friendObj.phone}}</td>
19758         </tr>
19759       </table>
19760     </file>
19761     <file name="protractor.js" type="protractor">
19762       var expectFriendNames = function(expectedNames, key) {
19763         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
19764           arr.forEach(function(wd, i) {
19765             expect(wd.getText()).toMatch(expectedNames[i]);
19766           });
19767         });
19768       };
19769
19770       it('should search across all fields when filtering with a string', function() {
19771         var searchText = element(by.model('searchText'));
19772         searchText.clear();
19773         searchText.sendKeys('m');
19774         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
19775
19776         searchText.clear();
19777         searchText.sendKeys('76');
19778         expectFriendNames(['John', 'Julie'], 'friend');
19779       });
19780
19781       it('should search in specific fields when filtering with a predicate object', function() {
19782         var searchAny = element(by.model('search.$'));
19783         searchAny.clear();
19784         searchAny.sendKeys('i');
19785         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
19786       });
19787       it('should use a equal comparison when comparator is true', function() {
19788         var searchName = element(by.model('search.name'));
19789         var strict = element(by.model('strict'));
19790         searchName.clear();
19791         searchName.sendKeys('Julie');
19792         strict.click();
19793         expectFriendNames(['Julie'], 'friendObj');
19794       });
19795     </file>
19796   </example>
19797 */
19798function filterFilter() {
19799  return function(array, expression, comparator) {
19800    if (!isArray(array)) return array;
19801
19802    var comparatorType = typeof(comparator),
19803        predicates = [];
19804
19805    predicates.check = function(value) {
19806      for (var j = 0; j < predicates.length; j++) {
19807        if(!predicates[j](value)) {
19808          return false;
19809        }
19810      }
19811      return true;
19812    };
19813
19814    if (comparatorType !== 'function') {
19815      if (comparatorType === 'boolean' && comparator) {
19816        comparator = function(obj, text) {
19817          return angular.equals(obj, text);
19818        };
19819      } else {
19820        comparator = function(obj, text) {
19821          if (obj && text && typeof obj === 'object' && typeof text === 'object') {
19822            for (var objKey in obj) {
19823              if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
19824                  comparator(obj[objKey], text[objKey])) {
19825                return true;
19826              }
19827            }
19828            return false;
19829          }
19830          text = (''+text).toLowerCase();
19831          return (''+obj).toLowerCase().indexOf(text) > -1;
19832        };
19833      }
19834    }
19835
19836    var search = function(obj, text){
19837      if (typeof text == 'string' && text.charAt(0) === '!') {
19838        return !search(obj, text.substr(1));
19839      }
19840      switch (typeof obj) {
19841        case "boolean":
19842        case "number":
19843        case "string":
19844          return comparator(obj, text);
19845        case "object":
19846          switch (typeof text) {
19847            case "object":
19848              return comparator(obj, text);
19849            default:
19850              for ( var objKey in obj) {
19851                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
19852                  return true;
19853                }
19854              }
19855              break;
19856          }
19857          return false;
19858        case "array":
19859          for ( var i = 0; i < obj.length; i++) {
19860            if (search(obj[i], text)) {
19861              return true;
19862            }
19863          }
19864          return false;
19865        default:
19866          return false;
19867      }
19868    };
19869    switch (typeof expression) {
19870      case "boolean":
19871      case "number":
19872      case "string":
19873        // Set up expression object and fall through
19874        expression = {$:expression};
19875        // jshint -W086
19876      case "object":
19877        // jshint +W086
19878        for (var key in expression) {
19879          (function(path) {
19880            if (typeof expression[path] === 'undefined') return;
19881            predicates.push(function(value) {
19882              return search(path == '$' ? value : (value && value[path]), expression[path]);
19883            });
19884          })(key);
19885        }
19886        break;
19887      case 'function':
19888        predicates.push(expression);
19889        break;
19890      default:
19891        return array;
19892    }
19893    var filtered = [];
19894    for ( var j = 0; j < array.length; j++) {
19895      var value = array[j];
19896      if (predicates.check(value)) {
19897        filtered.push(value);
19898      }
19899    }
19900    return filtered;
19901  };
19902}
19903
19904/**
19905 * @ngdoc filter
19906 * @name currency
19907 * @kind function
19908 *
19909 * @description
19910 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
19911 * symbol for current locale is used.
19912 *
19913 * @param {number} amount Input to filter.
19914 * @param {string=} symbol Currency symbol or identifier to be displayed.
19915 * @returns {string} Formatted number.
19916 *
19917 *
19918 * @example
19919   <example module="currencyExample">
19920     <file name="index.html">
19921       <script>
19922         angular.module('currencyExample', [])
19923           .controller('ExampleController', ['$scope', function($scope) {
19924             $scope.amount = 1234.56;
19925           }]);
19926       </script>
19927       <div ng-controller="ExampleController">
19928         <input type="number" ng-model="amount"> <br>
19929         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
19930         custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
19931       </div>
19932     </file>
19933     <file name="protractor.js" type="protractor">
19934       it('should init with 1234.56', function() {
19935         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
19936         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
19937       });
19938       it('should update', function() {
19939         if (browser.params.browser == 'safari') {
19940           // Safari does not understand the minus key. See
19941           // https://github.com/angular/protractor/issues/481
19942           return;
19943         }
19944         element(by.model('amount')).clear();
19945         element(by.model('amount')).sendKeys('-1234');
19946         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
19947         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
19948       });
19949     </file>
19950   </example>
19951 */
19952currencyFilter.$inject = ['$locale'];
19953function currencyFilter($locale) {
19954  var formats = $locale.NUMBER_FORMATS;
19955  return function(amount, currencySymbol){
19956    if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
19957    return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
19958                replace(/\u00A4/g, currencySymbol);
19959  };
19960}
19961
19962/**
19963 * @ngdoc filter
19964 * @name number
19965 * @kind function
19966 *
19967 * @description
19968 * Formats a number as text.
19969 *
19970 * If the input is not a number an empty string is returned.
19971 *
19972 * @param {number|string} number Number to format.
19973 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
19974 * If this is not provided then the fraction size is computed from the current locale's number
19975 * formatting pattern. In the case of the default locale, it will be 3.
19976 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
19977 *
19978 * @example
19979   <example module="numberFilterExample">
19980     <file name="index.html">
19981       <script>
19982         angular.module('numberFilterExample', [])
19983           .controller('ExampleController', ['$scope', function($scope) {
19984             $scope.val = 1234.56789;
19985           }]);
19986       </script>
19987       <div ng-controller="ExampleController">
19988         Enter number: <input ng-model='val'><br>
19989         Default formatting: <span id='number-default'>{{val | number}}</span><br>
19990         No fractions: <span>{{val | number:0}}</span><br>
19991         Negative number: <span>{{-val | number:4}}</span>
19992       </div>
19993     </file>
19994     <file name="protractor.js" type="protractor">
19995       it('should format numbers', function() {
19996         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
19997         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
19998         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
19999       });
20000
20001       it('should update', function() {
20002         element(by.model('val')).clear();
20003         element(by.model('val')).sendKeys('3374.333');
20004         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
20005         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
20006         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
20007      });
20008     </file>
20009   </example>
20010 */
20011
20012
20013numberFilter.$inject = ['$locale'];
20014function numberFilter($locale) {
20015  var formats = $locale.NUMBER_FORMATS;
20016  return function(number, fractionSize) {
20017    return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
20018      fractionSize);
20019  };
20020}
20021
20022var DECIMAL_SEP = '.';
20023function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
20024  if (number == null || !isFinite(number) || isObject(number)) return '';
20025
20026  var isNegative = number < 0;
20027  number = Math.abs(number);
20028  var numStr = number + '',
20029      formatedText = '',
20030      parts = [];
20031
20032  var hasExponent = false;
20033  if (numStr.indexOf('e') !== -1) {
20034    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
20035    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
20036      numStr = '0';
20037      number = 0;
20038    } else {
20039      formatedText = numStr;
20040      hasExponent = true;
20041    }
20042  }
20043
20044  if (!hasExponent) {
20045    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
20046
20047    // determine fractionSize if it is not specified
20048    if (isUndefined(fractionSize)) {
20049      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
20050    }
20051
20052    // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
20053    // inspired by:
20054    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
20055    number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
20056
20057    if (number === 0) {
20058      isNegative = false;
20059    }
20060
20061    var fraction = ('' + number).split(DECIMAL_SEP);
20062    var whole = fraction[0];
20063    fraction = fraction[1] || '';
20064
20065    var i, pos = 0,
20066        lgroup = pattern.lgSize,
20067        group = pattern.gSize;
20068
20069    if (whole.length >= (lgroup + group)) {
20070      pos = whole.length - lgroup;
20071      for (i = 0; i < pos; i++) {
20072        if ((pos - i)%group === 0 && i !== 0) {
20073          formatedText += groupSep;
20074        }
20075        formatedText += whole.charAt(i);
20076      }
20077    }
20078
20079    for (i = pos; i < whole.length; i++) {
20080      if ((whole.length - i)%lgroup === 0 && i !== 0) {
20081        formatedText += groupSep;
20082      }
20083      formatedText += whole.charAt(i);
20084    }
20085
20086    // format fraction part.
20087    while(fraction.length < fractionSize) {
20088      fraction += '0';
20089    }
20090
20091    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
20092  } else {
20093
20094    if (fractionSize > 0 && number > -1 && number < 1) {
20095      formatedText = number.toFixed(fractionSize);
20096    }
20097  }
20098
20099  parts.push(isNegative ? pattern.negPre : pattern.posPre);
20100  parts.push(formatedText);
20101  parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
20102  return parts.join('');
20103}
20104
20105function padNumber(num, digits, trim) {
20106  var neg = '';
20107  if (num < 0) {
20108    neg =  '-';
20109    num = -num;
20110  }
20111  num = '' + num;
20112  while(num.length < digits) num = '0' + num;
20113  if (trim)
20114    num = num.substr(num.length - digits);
20115  return neg + num;
20116}
20117
20118
20119function dateGetter(name, size, offset, trim) {
20120  offset = offset || 0;
20121  return function(date) {
20122    var value = date['get' + name]();
20123    if (offset > 0 || value > -offset)
20124      value += offset;
20125    if (value === 0 && offset == -12 ) value = 12;
20126    return padNumber(value, size, trim);
20127  };
20128}
20129
20130function dateStrGetter(name, shortForm) {
20131  return function(date, formats) {
20132    var value = date['get' + name]();
20133    var get = uppercase(shortForm ? ('SHORT' + name) : name);
20134
20135    return formats[get][value];
20136  };
20137}
20138
20139function timeZoneGetter(date) {
20140  var zone = -1 * date.getTimezoneOffset();
20141  var paddedZone = (zone >= 0) ? "+" : "";
20142
20143  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
20144                padNumber(Math.abs(zone % 60), 2);
20145
20146  return paddedZone;
20147}
20148
20149function ampmGetter(date, formats) {
20150  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
20151}
20152
20153var DATE_FORMATS = {
20154  yyyy: dateGetter('FullYear', 4),
20155    yy: dateGetter('FullYear', 2, 0, true),
20156     y: dateGetter('FullYear', 1),
20157  MMMM: dateStrGetter('Month'),
20158   MMM: dateStrGetter('Month', true),
20159    MM: dateGetter('Month', 2, 1),
20160     M: dateGetter('Month', 1, 1),
20161    dd: dateGetter('Date', 2),
20162     d: dateGetter('Date', 1),
20163    HH: dateGetter('Hours', 2),
20164     H: dateGetter('Hours', 1),
20165    hh: dateGetter('Hours', 2, -12),
20166     h: dateGetter('Hours', 1, -12),
20167    mm: dateGetter('Minutes', 2),
20168     m: dateGetter('Minutes', 1),
20169    ss: dateGetter('Seconds', 2),
20170     s: dateGetter('Seconds', 1),
20171     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
20172     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
20173   sss: dateGetter('Milliseconds', 3),
20174  EEEE: dateStrGetter('Day'),
20175   EEE: dateStrGetter('Day', true),
20176     a: ampmGetter,
20177     Z: timeZoneGetter
20178};
20179
20180var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
20181    NUMBER_STRING = /^\-?\d+$/;
20182
20183/**
20184 * @ngdoc filter
20185 * @name date
20186 * @kind function
20187 *
20188 * @description
20189 *   Formats `date` to a string based on the requested `format`.
20190 *
20191 *   `format` string can be composed of the following elements:
20192 *
20193 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
20194 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
20195 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
20196 *   * `'MMMM'`: Month in year (January-December)
20197 *   * `'MMM'`: Month in year (Jan-Dec)
20198 *   * `'MM'`: Month in year, padded (01-12)
20199 *   * `'M'`: Month in year (1-12)
20200 *   * `'dd'`: Day in month, padded (01-31)
20201 *   * `'d'`: Day in month (1-31)
20202 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
20203 *   * `'EEE'`: Day in Week, (Sun-Sat)
20204 *   * `'HH'`: Hour in day, padded (00-23)
20205 *   * `'H'`: Hour in day (0-23)
20206 *   * `'hh'`: Hour in am/pm, padded (01-12)
20207 *   * `'h'`: Hour in am/pm, (1-12)
20208 *   * `'mm'`: Minute in hour, padded (00-59)
20209 *   * `'m'`: Minute in hour (0-59)
20210 *   * `'ss'`: Second in minute, padded (00-59)
20211 *   * `'s'`: Second in minute (0-59)
20212 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
20213 *   * `'a'`: am/pm marker
20214 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
20215 *
20216 *   `format` string can also be one of the following predefined
20217 *   {@link guide/i18n localizable formats}:
20218 *
20219 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
20220 *     (e.g. Sep 3, 2010 12:05:08 pm)
20221 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
20222 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
20223 *     (e.g. Friday, September 3, 2010)
20224 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
20225 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
20226 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
20227 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
20228 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
20229 *
20230 *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
20231 *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
20232 *   (e.g. `"h 'o''clock'"`).
20233 *
20234 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
20235 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
20236 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
20237 *    specified in the string input, the time is considered to be in the local timezone.
20238 * @param {string=} format Formatting rules (see Description). If not specified,
20239 *    `mediumDate` is used.
20240 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
20241 *
20242 * @example
20243   <example>
20244     <file name="index.html">
20245       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
20246           <span>{{1288323623006 | date:'medium'}}</span><br>
20247       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
20248          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
20249       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
20250          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
20251       <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
20252          <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
20253     </file>
20254     <file name="protractor.js" type="protractor">
20255       it('should format date', function() {
20256         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
20257            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
20258         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
20259            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
20260         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
20261            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
20262         expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
20263            toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
20264       });
20265     </file>
20266   </example>
20267 */
20268dateFilter.$inject = ['$locale'];
20269function dateFilter($locale) {
20270
20271
20272  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
20273                     // 1        2       3         4          5          6          7          8  9     10      11
20274  function jsonStringToDate(string) {
20275    var match;
20276    if (match = string.match(R_ISO8601_STR)) {
20277      var date = new Date(0),
20278          tzHour = 0,
20279          tzMin  = 0,
20280          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
20281          timeSetter = match[8] ? date.setUTCHours : date.setHours;
20282
20283      if (match[9]) {
20284        tzHour = int(match[9] + match[10]);
20285        tzMin = int(match[9] + match[11]);
20286      }
20287      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
20288      var h = int(match[4]||0) - tzHour;
20289      var m = int(match[5]||0) - tzMin;
20290      var s = int(match[6]||0);
20291      var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
20292      timeSetter.call(date, h, m, s, ms);
20293      return date;
20294    }
20295    return string;
20296  }
20297
20298
20299  return function(date, format) {
20300    var text = '',
20301        parts = [],
20302        fn, match;
20303
20304    format = format || 'mediumDate';
20305    format = $locale.DATETIME_FORMATS[format] || format;
20306    if (isString(date)) {
20307      date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
20308    }
20309
20310    if (isNumber(date)) {
20311      date = new Date(date);
20312    }
20313
20314    if (!isDate(date)) {
20315      return date;
20316    }
20317
20318    while(format) {
20319      match = DATE_FORMATS_SPLIT.exec(format);
20320      if (match) {
20321        parts = concat(parts, match, 1);
20322        format = parts.pop();
20323      } else {
20324        parts.push(format);
20325        format = null;
20326      }
20327    }
20328
20329    forEach(parts, function(value){
20330      fn = DATE_FORMATS[value];
20331      text += fn ? fn(date, $locale.DATETIME_FORMATS)
20332                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
20333    });
20334
20335    return text;
20336  };
20337}
20338
20339
20340/**
20341 * @ngdoc filter
20342 * @name json
20343 * @kind function
20344 *
20345 * @description
20346 *   Allows you to convert a JavaScript object into JSON string.
20347 *
20348 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
20349 *   the binding is automatically converted to JSON.
20350 *
20351 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
20352 * @returns {string} JSON string.
20353 *
20354 *
20355 * @example
20356   <example>
20357     <file name="index.html">
20358       <pre>{{ {'name':'value'} | json }}</pre>
20359     </file>
20360     <file name="protractor.js" type="protractor">
20361       it('should jsonify filtered objects', function() {
20362         expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
20363       });
20364     </file>
20365   </example>
20366 *
20367 */
20368function jsonFilter() {
20369  return function(object) {
20370    return toJson(object, true);
20371  };
20372}
20373
20374
20375/**
20376 * @ngdoc filter
20377 * @name lowercase
20378 * @kind function
20379 * @description
20380 * Converts string to lowercase.
20381 * @see angular.lowercase
20382 */
20383var lowercaseFilter = valueFn(lowercase);
20384
20385
20386/**
20387 * @ngdoc filter
20388 * @name uppercase
20389 * @kind function
20390 * @description
20391 * Converts string to uppercase.
20392 * @see angular.uppercase
20393 */
20394var uppercaseFilter = valueFn(uppercase);
20395
20396/**
20397 * @ngdoc filter
20398 * @name limitTo
20399 * @kind function
20400 *
20401 * @description
20402 * Creates a new array or string containing only a specified number of elements. The elements
20403 * are taken from either the beginning or the end of the source array or string, as specified by
20404 * the value and sign (positive or negative) of `limit`.
20405 *
20406 * @param {Array|string} input Source array or string to be limited.
20407 * @param {string|number} limit The length of the returned array or string. If the `limit` number
20408 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
20409 *     If the number is negative, `limit` number  of items from the end of the source array/string
20410 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
20411 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
20412 *     had less than `limit` elements.
20413 *
20414 * @example
20415   <example module="limitToExample">
20416     <file name="index.html">
20417       <script>
20418         angular.module('limitToExample', [])
20419           .controller('ExampleController', ['$scope', function($scope) {
20420             $scope.numbers = [1,2,3,4,5,6,7,8,9];
20421             $scope.letters = "abcdefghi";
20422             $scope.numLimit = 3;
20423             $scope.letterLimit = 3;
20424           }]);
20425       </script>
20426       <div ng-controller="ExampleController">
20427         Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
20428         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
20429         Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
20430         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
20431       </div>
20432     </file>
20433     <file name="protractor.js" type="protractor">
20434       var numLimitInput = element(by.model('numLimit'));
20435       var letterLimitInput = element(by.model('letterLimit'));
20436       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
20437       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
20438
20439       it('should limit the number array to first three items', function() {
20440         expect(numLimitInput.getAttribute('value')).toBe('3');
20441         expect(letterLimitInput.getAttribute('value')).toBe('3');
20442         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
20443         expect(limitedLetters.getText()).toEqual('Output letters: abc');
20444       });
20445
20446       it('should update the output when -3 is entered', function() {
20447         numLimitInput.clear();
20448         numLimitInput.sendKeys('-3');
20449         letterLimitInput.clear();
20450         letterLimitInput.sendKeys('-3');
20451         expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
20452         expect(limitedLetters.getText()).toEqual('Output letters: ghi');
20453       });
20454
20455       it('should not exceed the maximum size of input array', function() {
20456         numLimitInput.clear();
20457         numLimitInput.sendKeys('100');
20458         letterLimitInput.clear();
20459         letterLimitInput.sendKeys('100');
20460         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
20461         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
20462       });
20463     </file>
20464   </example>
20465 */
20466function limitToFilter(){
20467  return function(input, limit) {
20468    if (!isArray(input) && !isString(input)) return input;
20469
20470    if (Math.abs(Number(limit)) === Infinity) {
20471      limit = Number(limit);
20472    } else {
20473      limit = int(limit);
20474    }
20475
20476    if (isString(input)) {
20477      //NaN check on limit
20478      if (limit) {
20479        return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
20480      } else {
20481        return "";
20482      }
20483    }
20484
20485    var out = [],
20486      i, n;
20487
20488    // if abs(limit) exceeds maximum length, trim it
20489    if (limit > input.length)
20490      limit = input.length;
20491    else if (limit < -input.length)
20492      limit = -input.length;
20493
20494    if (limit > 0) {
20495      i = 0;
20496      n = limit;
20497    } else {
20498      i = input.length + limit;
20499      n = input.length;
20500    }
20501
20502    for (; i<n; i++) {
20503      out.push(input[i]);
20504    }
20505
20506    return out;
20507  };
20508}
20509
20510/**
20511 * @ngdoc filter
20512 * @name orderBy
20513 * @kind function
20514 *
20515 * @description
20516 * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
20517 * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
20518 * correctly, make sure they are actually being saved as numbers and not strings.
20519 *
20520 * @param {Array} array The array to sort.
20521 * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
20522 *    used by the comparator to determine the order of elements.
20523 *
20524 *    Can be one of:
20525 *
20526 *    - `function`: Getter function. The result of this function will be sorted using the
20527 *      `<`, `=`, `>` operator.
20528 *    - `string`: An Angular expression. The result of this expression is used to compare elements
20529 *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
20530 *      3 first characters of a property called `name`). The result of a constant expression
20531 *      is interpreted as a property name to be used in comparisons (for example `"special name"`
20532 *      to sort object by the value of their `special name` property). An expression can be
20533 *      optionally prefixed with `+` or `-` to control ascending or descending sort order
20534 *      (for example, `+name` or `-name`).
20535 *    - `Array`: An array of function or string predicates. The first predicate in the array
20536 *      is used for sorting, but when two items are equivalent, the next predicate is used.
20537 *
20538 * @param {boolean=} reverse Reverse the order of the array.
20539 * @returns {Array} Sorted copy of the source array.
20540 *
20541 * @example
20542   <example module="orderByExample">
20543     <file name="index.html">
20544       <script>
20545         angular.module('orderByExample', [])
20546           .controller('ExampleController', ['$scope', function($scope) {
20547             $scope.friends =
20548                 [{name:'John', phone:'555-1212', age:10},
20549                  {name:'Mary', phone:'555-9876', age:19},
20550                  {name:'Mike', phone:'555-4321', age:21},
20551                  {name:'Adam', phone:'555-5678', age:35},
20552                  {name:'Julie', phone:'555-8765', age:29}];
20553             $scope.predicate = '-age';
20554           }]);
20555       </script>
20556       <div ng-controller="ExampleController">
20557         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
20558         <hr/>
20559         [ <a href="" ng-click="predicate=''">unsorted</a> ]
20560         <table class="friend">
20561           <tr>
20562             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
20563                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
20564             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
20565             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
20566           </tr>
20567           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
20568             <td>{{friend.name}}</td>
20569             <td>{{friend.phone}}</td>
20570             <td>{{friend.age}}</td>
20571           </tr>
20572         </table>
20573       </div>
20574     </file>
20575   </example>
20576 *
20577 * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
20578 * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
20579 * desired parameters.
20580 *
20581 * Example:
20582 *
20583 * @example
20584  <example module="orderByExample">
20585    <file name="index.html">
20586      <div ng-controller="ExampleController">
20587        <table class="friend">
20588          <tr>
20589            <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
20590              (<a href="" ng-click="order('-name',false)">^</a>)</th>
20591            <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
20592            <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
20593          </tr>
20594          <tr ng-repeat="friend in friends">
20595            <td>{{friend.name}}</td>
20596            <td>{{friend.phone}}</td>
20597            <td>{{friend.age}}</td>
20598          </tr>
20599        </table>
20600      </div>
20601    </file>
20602
20603    <file name="script.js">
20604      angular.module('orderByExample', [])
20605        .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
20606          var orderBy = $filter('orderBy');
20607          $scope.friends = [
20608            { name: 'John',    phone: '555-1212',    age: 10 },
20609            { name: 'Mary',    phone: '555-9876',    age: 19 },
20610            { name: 'Mike',    phone: '555-4321',    age: 21 },
20611            { name: 'Adam',    phone: '555-5678',    age: 35 },
20612            { name: 'Julie',   phone: '555-8765',    age: 29 }
20613          ];
20614          $scope.order = function(predicate, reverse) {
20615            $scope.friends = orderBy($scope.friends, predicate, reverse);
20616          };
20617          $scope.order('-age',false);
20618        }]);
20619    </file>
20620</example>
20621 */
20622orderByFilter.$inject = ['$parse'];
20623function orderByFilter($parse){
20624  return function(array, sortPredicate, reverseOrder) {
20625    if (!(isArrayLike(array))) return array;
20626    if (!sortPredicate) return array;
20627    sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
20628    sortPredicate = map(sortPredicate, function(predicate){
20629      var descending = false, get = predicate || identity;
20630      if (isString(predicate)) {
20631        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
20632          descending = predicate.charAt(0) == '-';
20633          predicate = predicate.substring(1);
20634        }
20635        get = $parse(predicate);
20636        if (get.constant) {
20637          var key = get();
20638          return reverseComparator(function(a,b) {
20639            return compare(a[key], b[key]);
20640          }, descending);
20641        }
20642      }
20643      return reverseComparator(function(a,b){
20644        return compare(get(a),get(b));
20645      }, descending);
20646    });
20647    var arrayCopy = [];
20648    for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
20649    return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
20650
20651    function comparator(o1, o2){
20652      for ( var i = 0; i < sortPredicate.length; i++) {
20653        var comp = sortPredicate[i](o1, o2);
20654        if (comp !== 0) return comp;
20655      }
20656      return 0;
20657    }
20658    function reverseComparator(comp, descending) {
20659      return toBoolean(descending)
20660          ? function(a,b){return comp(b,a);}
20661          : comp;
20662    }
20663    function compare(v1, v2){
20664      var t1 = typeof v1;
20665      var t2 = typeof v2;
20666      if (t1 == t2) {
20667        if (isDate(v1) && isDate(v2)) {
20668          v1 = v1.valueOf();
20669          v2 = v2.valueOf();
20670        }
20671        if (t1 == "string") {
20672           v1 = v1.toLowerCase();
20673           v2 = v2.toLowerCase();
20674        }
20675        if (v1 === v2) return 0;
20676        return v1 < v2 ? -1 : 1;
20677      } else {
20678        return t1 < t2 ? -1 : 1;
20679      }
20680    }
20681  };
20682}
20683
20684function ngDirective(directive) {
20685  if (isFunction(directive)) {
20686    directive = {
20687      link: directive
20688    };
20689  }
20690  directive.restrict = directive.restrict || 'AC';
20691  return valueFn(directive);
20692}
20693
20694/**
20695 * @ngdoc directive
20696 * @name a
20697 * @restrict E
20698 *
20699 * @description
20700 * Modifies the default behavior of the html A tag so that the default action is prevented when
20701 * the href attribute is empty.
20702 *
20703 * This change permits the easy creation of action links with the `ngClick` directive
20704 * without changing the location or causing page reloads, e.g.:
20705 * `<a href="" ng-click="list.addItem()">Add Item</a>`
20706 */
20707var htmlAnchorDirective = valueFn({
20708  restrict: 'E',
20709  compile: function(element, attr) {
20710
20711    if (msie <= 8) {
20712
20713      // turn <a href ng-click="..">link</a> into a stylable link in IE
20714      // but only if it doesn't have name attribute, in which case it's an anchor
20715      if (!attr.href && !attr.name) {
20716        attr.$set('href', '');
20717      }
20718
20719      // add a comment node to anchors to workaround IE bug that causes element content to be reset
20720      // to new attribute content if attribute is updated with value containing @ and element also
20721      // contains value with @
20722      // see issue #1949
20723      element.append(document.createComment('IE fix'));
20724    }
20725
20726    if (!attr.href && !attr.xlinkHref && !attr.name) {
20727      return function(scope, element) {
20728        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
20729        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
20730                   'xlink:href' : 'href';
20731        element.on('click', function(event){
20732          // if we have no href url, then don't navigate anywhere.
20733          if (!element.attr(href)) {
20734            event.preventDefault();
20735          }
20736        });
20737      };
20738    }
20739  }
20740});
20741
20742/**
20743 * @ngdoc directive
20744 * @name ngHref
20745 * @restrict A
20746 * @priority 99
20747 *
20748 * @description
20749 * Using Angular markup like `{{hash}}` in an href attribute will
20750 * make the link go to the wrong URL if the user clicks it before
20751 * Angular has a chance to replace the `{{hash}}` markup with its
20752 * value. Until Angular replaces the markup the link will be broken
20753 * and will most likely return a 404 error.
20754 *
20755 * The `ngHref` directive solves this problem.
20756 *
20757 * The wrong way to write it:
20758 * ```html
20759 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
20760 * ```
20761 *
20762 * The correct way to write it:
20763 * ```html
20764 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
20765 * ```
20766 *
20767 * @element A
20768 * @param {template} ngHref any string which can contain `{{}}` markup.
20769 *
20770 * @example
20771 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
20772 * in links and their different behaviors:
20773    <example>
20774      <file name="index.html">
20775        <input ng-model="value" /><br />
20776        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
20777        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
20778        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
20779        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
20780        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
20781        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
20782      </file>
20783      <file name="protractor.js" type="protractor">
20784        it('should execute ng-click but not reload when href without value', function() {
20785          element(by.id('link-1')).click();
20786          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
20787          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
20788        });
20789
20790        it('should execute ng-click but not reload when href empty string', function() {
20791          element(by.id('link-2')).click();
20792          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
20793          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
20794        });
20795
20796        it('should execute ng-click and change url when ng-href specified', function() {
20797          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
20798
20799          element(by.id('link-3')).click();
20800
20801          // At this point, we navigate away from an Angular page, so we need
20802          // to use browser.driver to get the base webdriver.
20803
20804          browser.wait(function() {
20805            return browser.driver.getCurrentUrl().then(function(url) {
20806              return url.match(/\/123$/);
20807            });
20808          }, 5000, 'page should navigate to /123');
20809        });
20810
20811        xit('should execute ng-click but not reload when href empty string and name specified', function() {
20812          element(by.id('link-4')).click();
20813          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
20814          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
20815        });
20816
20817        it('should execute ng-click but not reload when no href but name specified', function() {
20818          element(by.id('link-5')).click();
20819          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
20820          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
20821        });
20822
20823        it('should only change url when only ng-href', function() {
20824          element(by.model('value')).clear();
20825          element(by.model('value')).sendKeys('6');
20826          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
20827
20828          element(by.id('link-6')).click();
20829
20830          // At this point, we navigate away from an Angular page, so we need
20831          // to use browser.driver to get the base webdriver.
20832          browser.wait(function() {
20833            return browser.driver.getCurrentUrl().then(function(url) {
20834              return url.match(/\/6$/);
20835            });
20836          }, 5000, 'page should navigate to /6');
20837        });
20838      </file>
20839    </example>
20840 */
20841
20842/**
20843 * @ngdoc directive
20844 * @name ngSrc
20845 * @restrict A
20846 * @priority 99
20847 *
20848 * @description
20849 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
20850 * work right: The browser will fetch from the URL with the literal
20851 * text `{{hash}}` until Angular replaces the expression inside
20852 * `{{hash}}`. The `ngSrc` directive solves this problem.
20853 *
20854 * The buggy way to write it:
20855 * ```html
20856 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
20857 * ```
20858 *
20859 * The correct way to write it:
20860 * ```html
20861 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
20862 * ```
20863 *
20864 * @element IMG
20865 * @param {template} ngSrc any string which can contain `{{}}` markup.
20866 */
20867
20868/**
20869 * @ngdoc directive
20870 * @name ngSrcset
20871 * @restrict A
20872 * @priority 99
20873 *
20874 * @description
20875 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
20876 * work right: The browser will fetch from the URL with the literal
20877 * text `{{hash}}` until Angular replaces the expression inside
20878 * `{{hash}}`. The `ngSrcset` directive solves this problem.
20879 *
20880 * The buggy way to write it:
20881 * ```html
20882 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
20883 * ```
20884 *
20885 * The correct way to write it:
20886 * ```html
20887 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
20888 * ```
20889 *
20890 * @element IMG
20891 * @param {template} ngSrcset any string which can contain `{{}}` markup.
20892 */
20893
20894/**
20895 * @ngdoc directive
20896 * @name ngDisabled
20897 * @restrict A
20898 * @priority 100
20899 *
20900 * @description
20901 *
20902 * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
20903 * ```html
20904 * <div ng-init="scope = { isDisabled: false }">
20905 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
20906 * </div>
20907 * ```
20908 *
20909 * The HTML specification does not require browsers to preserve the values of boolean attributes
20910 * such as disabled. (Their presence means true and their absence means false.)
20911 * If we put an Angular interpolation expression into such an attribute then the
20912 * binding information would be lost when the browser removes the attribute.
20913 * The `ngDisabled` directive solves this problem for the `disabled` attribute.
20914 * This complementary directive is not removed by the browser and so provides
20915 * a permanent reliable place to store the binding information.
20916 *
20917 * @example
20918    <example>
20919      <file name="index.html">
20920        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
20921        <button ng-model="button" ng-disabled="checked">Button</button>
20922      </file>
20923      <file name="protractor.js" type="protractor">
20924        it('should toggle button', function() {
20925          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
20926          element(by.model('checked')).click();
20927          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
20928        });
20929      </file>
20930    </example>
20931 *
20932 * @element INPUT
20933 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
20934 *     then special attribute "disabled" will be set on the element
20935 */
20936
20937
20938/**
20939 * @ngdoc directive
20940 * @name ngChecked
20941 * @restrict A
20942 * @priority 100
20943 *
20944 * @description
20945 * The HTML specification does not require browsers to preserve the values of boolean attributes
20946 * such as checked. (Their presence means true and their absence means false.)
20947 * If we put an Angular interpolation expression into such an attribute then the
20948 * binding information would be lost when the browser removes the attribute.
20949 * The `ngChecked` directive solves this problem for the `checked` attribute.
20950 * This complementary directive is not removed by the browser and so provides
20951 * a permanent reliable place to store the binding information.
20952 * @example
20953    <example>
20954      <file name="index.html">
20955        Check me to check both: <input type="checkbox" ng-model="master"><br/>
20956        <input id="checkSlave" type="checkbox" ng-checked="master">
20957      </file>
20958      <file name="protractor.js" type="protractor">
20959        it('should check both checkBoxes', function() {
20960          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
20961          element(by.model('master')).click();
20962          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
20963        });
20964      </file>
20965    </example>
20966 *
20967 * @element INPUT
20968 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
20969 *     then special attribute "checked" will be set on the element
20970 */
20971
20972
20973/**
20974 * @ngdoc directive
20975 * @name ngReadonly
20976 * @restrict A
20977 * @priority 100
20978 *
20979 * @description
20980 * The HTML specification does not require browsers to preserve the values of boolean attributes
20981 * such as readonly. (Their presence means true and their absence means false.)
20982 * If we put an Angular interpolation expression into such an attribute then the
20983 * binding information would be lost when the browser removes the attribute.
20984 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
20985 * This complementary directive is not removed by the browser and so provides
20986 * a permanent reliable place to store the binding information.
20987 * @example
20988    <example>
20989      <file name="index.html">
20990        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
20991        <input type="text" ng-readonly="checked" value="I'm Angular"/>
20992      </file>
20993      <file name="protractor.js" type="protractor">
20994        it('should toggle readonly attr', function() {
20995          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
20996          element(by.model('checked')).click();
20997          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
20998        });
20999      </file>
21000    </example>
21001 *
21002 * @element INPUT
21003 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
21004 *     then special attribute "readonly" will be set on the element
21005 */
21006
21007
21008/**
21009 * @ngdoc directive
21010 * @name ngSelected
21011 * @restrict A
21012 * @priority 100
21013 *
21014 * @description
21015 * The HTML specification does not require browsers to preserve the values of boolean attributes
21016 * such as selected. (Their presence means true and their absence means false.)
21017 * If we put an Angular interpolation expression into such an attribute then the
21018 * binding information would be lost when the browser removes the attribute.
21019 * The `ngSelected` directive solves this problem for the `selected` attribute.
21020 * This complementary directive is not removed by the browser and so provides
21021 * a permanent reliable place to store the binding information.
21022 *
21023 * @example
21024    <example>
21025      <file name="index.html">
21026        Check me to select: <input type="checkbox" ng-model="selected"><br/>
21027        <select>
21028          <option>Hello!</option>
21029          <option id="greet" ng-selected="selected">Greetings!</option>
21030        </select>
21031      </file>
21032      <file name="protractor.js" type="protractor">
21033        it('should select Greetings!', function() {
21034          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
21035          element(by.model('selected')).click();
21036          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
21037        });
21038      </file>
21039    </example>
21040 *
21041 * @element OPTION
21042 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
21043 *     then special attribute "selected" will be set on the element
21044 */
21045
21046/**
21047 * @ngdoc directive
21048 * @name ngOpen
21049 * @restrict A
21050 * @priority 100
21051 *
21052 * @description
21053 * The HTML specification does not require browsers to preserve the values of boolean attributes
21054 * such as open. (Their presence means true and their absence means false.)
21055 * If we put an Angular interpolation expression into such an attribute then the
21056 * binding information would be lost when the browser removes the attribute.
21057 * The `ngOpen` directive solves this problem for the `open` attribute.
21058 * This complementary directive is not removed by the browser and so provides
21059 * a permanent reliable place to store the binding information.
21060 * @example
21061     <example>
21062       <file name="index.html">
21063         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
21064         <details id="details" ng-open="open">
21065            <summary>Show/Hide me</summary>
21066         </details>
21067       </file>
21068       <file name="protractor.js" type="protractor">
21069         it('should toggle open', function() {
21070           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
21071           element(by.model('open')).click();
21072           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
21073         });
21074       </file>
21075     </example>
21076 *
21077 * @element DETAILS
21078 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
21079 *     then special attribute "open" will be set on the element
21080 */
21081
21082var ngAttributeAliasDirectives = {};
21083
21084
21085// boolean attrs are evaluated
21086forEach(BOOLEAN_ATTR, function(propName, attrName) {
21087  // binding to multiple is not supported
21088  if (propName == "multiple") return;
21089
21090  var normalized = directiveNormalize('ng-' + attrName);
21091  ngAttributeAliasDirectives[normalized] = function() {
21092    return {
21093      priority: 100,
21094      link: function(scope, element, attr) {
21095        scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
21096          attr.$set(attrName, !!value);
21097        });
21098      }
21099    };
21100  };
21101});
21102
21103
21104// ng-src, ng-srcset, ng-href are interpolated
21105forEach(['src', 'srcset', 'href'], function(attrName) {
21106  var normalized = directiveNormalize('ng-' + attrName);
21107  ngAttributeAliasDirectives[normalized] = function() {
21108    return {
21109      priority: 99, // it needs to run after the attributes are interpolated
21110      link: function(scope, element, attr) {
21111        var propName = attrName,
21112            name = attrName;
21113
21114        if (attrName === 'href' &&
21115            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
21116          name = 'xlinkHref';
21117          attr.$attr[name] = 'xlink:href';
21118          propName = null;
21119        }
21120
21121        attr.$observe(normalized, function(value) {
21122          if (!value) {
21123            if (attrName === 'href') {
21124              attr.$set(name, null);
21125            }
21126            return;
21127          }
21128
21129          attr.$set(name, value);
21130
21131          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
21132          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
21133          // to set the property as well to achieve the desired effect.
21134          // we use attr[attrName] value since $set can sanitize the url.
21135          if (msie && propName) element.prop(propName, attr[name]);
21136        });
21137      }
21138    };
21139  };
21140});
21141
21142/* global -nullFormCtrl */
21143var nullFormCtrl = {
21144  $addControl: noop,
21145  $removeControl: noop,
21146  $setValidity: noop,
21147  $setDirty: noop,
21148  $setPristine: noop
21149};
21150
21151/**
21152 * @ngdoc type
21153 * @name form.FormController
21154 *
21155 * @property {boolean} $pristine True if user has not interacted with the form yet.
21156 * @property {boolean} $dirty True if user has already interacted with the form.
21157 * @property {boolean} $valid True if all of the containing forms and controls are valid.
21158 * @property {boolean} $invalid True if at least one containing control or form is invalid.
21159 *
21160 * @property {Object} $error Is an object hash, containing references to all invalid controls or
21161 *  forms, where:
21162 *
21163 *  - keys are validation tokens (error names),
21164 *  - values are arrays of controls or forms that are invalid for given error name.
21165 *
21166 *
21167 *  Built-in validation tokens:
21168 *
21169 *  - `email`
21170 *  - `max`
21171 *  - `maxlength`
21172 *  - `min`
21173 *  - `minlength`
21174 *  - `number`
21175 *  - `pattern`
21176 *  - `required`
21177 *  - `url`
21178 *
21179 * @description
21180 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
21181 * such as being valid/invalid or dirty/pristine.
21182 *
21183 * Each {@link ng.directive:form form} directive creates an instance
21184 * of `FormController`.
21185 *
21186 */
21187//asks for $scope to fool the BC controller module
21188FormController.$inject = ['$element', '$attrs', '$scope', '$animate'];
21189function FormController(element, attrs, $scope, $animate) {
21190  var form = this,
21191      parentForm = element.parent().controller('form') || nullFormCtrl,
21192      invalidCount = 0, // used to easily determine if we are valid
21193      errors = form.$error = {},
21194      controls = [];
21195
21196  // init state
21197  form.$name = attrs.name || attrs.ngForm;
21198  form.$dirty = false;
21199  form.$pristine = true;
21200  form.$valid = true;
21201  form.$invalid = false;
21202
21203  parentForm.$addControl(form);
21204
21205  // Setup initial state of the control
21206  element.addClass(PRISTINE_CLASS);
21207  toggleValidCss(true);
21208
21209  // convenience method for easy toggling of classes
21210  function toggleValidCss(isValid, validationErrorKey) {
21211    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
21212    $animate.setClass(element,
21213      (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey,
21214      (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
21215  }
21216
21217  /**
21218   * @ngdoc method
21219   * @name form.FormController#$addControl
21220   *
21221   * @description
21222   * Register a control with the form.
21223   *
21224   * Input elements using ngModelController do this automatically when they are linked.
21225   */
21226  form.$addControl = function(control) {
21227    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
21228    // and not added to the scope.  Now we throw an error.
21229    assertNotHasOwnProperty(control.$name, 'input');
21230    controls.push(control);
21231
21232    if (control.$name) {
21233      form[control.$name] = control;
21234    }
21235  };
21236
21237  /**
21238   * @ngdoc method
21239   * @name form.FormController#$removeControl
21240   *
21241   * @description
21242   * Deregister a control from the form.
21243   *
21244   * Input elements using ngModelController do this automatically when they are destroyed.
21245   */
21246  form.$removeControl = function(control) {
21247    if (control.$name && form[control.$name] === control) {
21248      delete form[control.$name];
21249    }
21250    forEach(errors, function(queue, validationToken) {
21251      form.$setValidity(validationToken, true, control);
21252    });
21253
21254    arrayRemove(controls, control);
21255  };
21256
21257  /**
21258   * @ngdoc method
21259   * @name form.FormController#$setValidity
21260   *
21261   * @description
21262   * Sets the validity of a form control.
21263   *
21264   * This method will also propagate to parent forms.
21265   */
21266  form.$setValidity = function(validationToken, isValid, control) {
21267    var queue = errors[validationToken];
21268
21269    if (isValid) {
21270      if (queue) {
21271        arrayRemove(queue, control);
21272        if (!queue.length) {
21273          invalidCount--;
21274          if (!invalidCount) {
21275            toggleValidCss(isValid);
21276            form.$valid = true;
21277            form.$invalid = false;
21278          }
21279          errors[validationToken] = false;
21280          toggleValidCss(true, validationToken);
21281          parentForm.$setValidity(validationToken, true, form);
21282        }
21283      }
21284
21285    } else {
21286      if (!invalidCount) {
21287        toggleValidCss(isValid);
21288      }
21289      if (queue) {
21290        if (includes(queue, control)) return;
21291      } else {
21292        errors[validationToken] = queue = [];
21293        invalidCount++;
21294        toggleValidCss(false, validationToken);
21295        parentForm.$setValidity(validationToken, false, form);
21296      }
21297      queue.push(control);
21298
21299      form.$valid = false;
21300      form.$invalid = true;
21301    }
21302  };
21303
21304  /**
21305   * @ngdoc method
21306   * @name form.FormController#$setDirty
21307   *
21308   * @description
21309   * Sets the form to a dirty state.
21310   *
21311   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
21312   * state (ng-dirty class). This method will also propagate to parent forms.
21313   */
21314  form.$setDirty = function() {
21315    $animate.removeClass(element, PRISTINE_CLASS);
21316    $animate.addClass(element, DIRTY_CLASS);
21317    form.$dirty = true;
21318    form.$pristine = false;
21319    parentForm.$setDirty();
21320  };
21321
21322  /**
21323   * @ngdoc method
21324   * @name form.FormController#$setPristine
21325   *
21326   * @description
21327   * Sets the form to its pristine state.
21328   *
21329   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
21330   * state (ng-pristine class). This method will also propagate to all the controls contained
21331   * in this form.
21332   *
21333   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
21334   * saving or resetting it.
21335   */
21336  form.$setPristine = function () {
21337    $animate.removeClass(element, DIRTY_CLASS);
21338    $animate.addClass(element, PRISTINE_CLASS);
21339    form.$dirty = false;
21340    form.$pristine = true;
21341    forEach(controls, function(control) {
21342      control.$setPristine();
21343    });
21344  };
21345}
21346
21347
21348/**
21349 * @ngdoc directive
21350 * @name ngForm
21351 * @restrict EAC
21352 *
21353 * @description
21354 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
21355 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
21356 * sub-group of controls needs to be determined.
21357 *
21358 * Note: the purpose of `ngForm` is to group controls,
21359 * but not to be a replacement for the `<form>` tag with all of its capabilities
21360 * (e.g. posting to the server, ...).
21361 *
21362 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
21363 *                       related scope, under this name.
21364 *
21365 */
21366
21367 /**
21368 * @ngdoc directive
21369 * @name form
21370 * @restrict E
21371 *
21372 * @description
21373 * Directive that instantiates
21374 * {@link form.FormController FormController}.
21375 *
21376 * If the `name` attribute is specified, the form controller is published onto the current scope under
21377 * this name.
21378 *
21379 * # Alias: {@link ng.directive:ngForm `ngForm`}
21380 *
21381 * In Angular forms can be nested. This means that the outer form is valid when all of the child
21382 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
21383 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
21384 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
21385 * using Angular validation directives in forms that are dynamically generated using the
21386 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
21387 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
21388 * `ngForm` directive and nest these in an outer `form` element.
21389 *
21390 *
21391 * # CSS classes
21392 *  - `ng-valid` is set if the form is valid.
21393 *  - `ng-invalid` is set if the form is invalid.
21394 *  - `ng-pristine` is set if the form is pristine.
21395 *  - `ng-dirty` is set if the form is dirty.
21396 *
21397 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
21398 *
21399 *
21400 * # Submitting a form and preventing the default action
21401 *
21402 * Since the role of forms in client-side Angular applications is different than in classical
21403 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
21404 * page reload that sends the data to the server. Instead some javascript logic should be triggered
21405 * to handle the form submission in an application-specific way.
21406 *
21407 * For this reason, Angular prevents the default action (form submission to the server) unless the
21408 * `<form>` element has an `action` attribute specified.
21409 *
21410 * You can use one of the following two ways to specify what javascript method should be called when
21411 * a form is submitted:
21412 *
21413 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
21414 * - {@link ng.directive:ngClick ngClick} directive on the first
21415  *  button or input field of type submit (input[type=submit])
21416 *
21417 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
21418 * or {@link ng.directive:ngClick ngClick} directives.
21419 * This is because of the following form submission rules in the HTML specification:
21420 *
21421 * - If a form has only one input field then hitting enter in this field triggers form submit
21422 * (`ngSubmit`)
21423 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
21424 * doesn't trigger submit
21425 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
21426 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
21427 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
21428 *
21429 *
21430 * ## Animation Hooks
21431 *
21432 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
21433 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
21434 * other validations that are performed within the form. Animations in ngForm are similar to how
21435 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
21436 * as JS animations.
21437 *
21438 * The following example shows a simple way to utilize CSS transitions to style a form element
21439 * that has been rendered as invalid after it has been validated:
21440 *
21441 * <pre>
21442 * //be sure to include ngAnimate as a module to hook into more
21443 * //advanced animations
21444 * .my-form {
21445 *   transition:0.5s linear all;
21446 *   background: white;
21447 * }
21448 * .my-form.ng-invalid {
21449 *   background: red;
21450 *   color:white;
21451 * }
21452 * </pre>
21453 *
21454 * @example
21455    <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
21456      <file name="index.html">
21457       <script>
21458         angular.module('formExample', [])
21459           .controller('FormController', ['$scope', function($scope) {
21460             $scope.userType = 'guest';
21461           }]);
21462       </script>
21463       <style>
21464        .my-form {
21465          -webkit-transition:all linear 0.5s;
21466          transition:all linear 0.5s;
21467          background: transparent;
21468        }
21469        .my-form.ng-invalid {
21470          background: red;
21471        }
21472       </style>
21473       <form name="myForm" ng-controller="FormController" class="my-form">
21474         userType: <input name="input" ng-model="userType" required>
21475         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
21476         <tt>userType = {{userType}}</tt><br>
21477         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
21478         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
21479         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
21480         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
21481        </form>
21482      </file>
21483      <file name="protractor.js" type="protractor">
21484        it('should initialize to model', function() {
21485          var userType = element(by.binding('userType'));
21486          var valid = element(by.binding('myForm.input.$valid'));
21487
21488          expect(userType.getText()).toContain('guest');
21489          expect(valid.getText()).toContain('true');
21490        });
21491
21492        it('should be invalid if empty', function() {
21493          var userType = element(by.binding('userType'));
21494          var valid = element(by.binding('myForm.input.$valid'));
21495          var userInput = element(by.model('userType'));
21496
21497          userInput.clear();
21498          userInput.sendKeys('');
21499
21500          expect(userType.getText()).toEqual('userType =');
21501          expect(valid.getText()).toContain('false');
21502        });
21503      </file>
21504    </example>
21505 *
21506 * @param {string=} name Name of the form. If specified, the form controller will be published into
21507 *                       related scope, under this name.
21508 */
21509var formDirectiveFactory = function(isNgForm) {
21510  return ['$timeout', function($timeout) {
21511    var formDirective = {
21512      name: 'form',
21513      restrict: isNgForm ? 'EAC' : 'E',
21514      controller: FormController,
21515      compile: function() {
21516        return {
21517          pre: function(scope, formElement, attr, controller) {
21518            if (!attr.action) {
21519              // we can't use jq events because if a form is destroyed during submission the default
21520              // action is not prevented. see #1238
21521              //
21522              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
21523              // page reload if the form was destroyed by submission of the form via a click handler
21524              // on a button in the form. Looks like an IE9 specific bug.
21525              var preventDefaultListener = function(event) {
21526                event.preventDefault
21527                  ? event.preventDefault()
21528                  : event.returnValue = false; // IE
21529              };
21530
21531              addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
21532
21533              // unregister the preventDefault listener so that we don't not leak memory but in a
21534              // way that will achieve the prevention of the default action.
21535              formElement.on('$destroy', function() {
21536                $timeout(function() {
21537                  removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
21538                }, 0, false);
21539              });
21540            }
21541
21542            var parentFormCtrl = formElement.parent().controller('form'),
21543                alias = attr.name || attr.ngForm;
21544
21545            if (alias) {
21546              setter(scope, alias, controller, alias);
21547            }
21548            if (parentFormCtrl) {
21549              formElement.on('$destroy', function() {
21550                parentFormCtrl.$removeControl(controller);
21551                if (alias) {
21552                  setter(scope, alias, undefined, alias);
21553                }
21554                extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
21555              });
21556            }
21557          }
21558        };
21559      }
21560    };
21561
21562    return formDirective;
21563  }];
21564};
21565
21566var formDirective = formDirectiveFactory();
21567var ngFormDirective = formDirectiveFactory(true);
21568
21569/* global VALID_CLASS: true,
21570    INVALID_CLASS: true,
21571    PRISTINE_CLASS: true,
21572    DIRTY_CLASS: true
21573*/
21574
21575var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
21576var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
21577var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
21578
21579var inputType = {
21580
21581  /**
21582   * @ngdoc input
21583   * @name input[text]
21584   *
21585   * @description
21586   * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
21587   *
21588   * *NOTE* Not every feature offered is available for all input types.
21589   *
21590   * @param {string} ngModel Assignable angular expression to data-bind to.
21591   * @param {string=} name Property name of the form under which the control is published.
21592   * @param {string=} required Adds `required` validation error key if the value is not entered.
21593   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21594   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21595   *    `required` when you want to data-bind to the `required` attribute.
21596   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21597   *    minlength.
21598   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21599   *    maxlength.
21600   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
21601   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
21602   *    patterns defined as scope expressions.
21603   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21604   *    interaction with the input element.
21605   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
21606   *    This parameter is ignored for input[type=password] controls, which will never trim the
21607   *    input.
21608   *
21609   * @example
21610      <example name="text-input-directive" module="textInputExample">
21611        <file name="index.html">
21612         <script>
21613           angular.module('textInputExample', [])
21614             .controller('ExampleController', ['$scope', function($scope) {
21615               $scope.text = 'guest';
21616               $scope.word = /^\s*\w*\s*$/;
21617             }]);
21618         </script>
21619         <form name="myForm" ng-controller="ExampleController">
21620           Single word: <input type="text" name="input" ng-model="text"
21621                               ng-pattern="word" required ng-trim="false">
21622           <span class="error" ng-show="myForm.input.$error.required">
21623             Required!</span>
21624           <span class="error" ng-show="myForm.input.$error.pattern">
21625             Single word only!</span>
21626
21627           <tt>text = {{text}}</tt><br/>
21628           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21629           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21630           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21631           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21632          </form>
21633        </file>
21634        <file name="protractor.js" type="protractor">
21635          var text = element(by.binding('text'));
21636          var valid = element(by.binding('myForm.input.$valid'));
21637          var input = element(by.model('text'));
21638
21639          it('should initialize to model', function() {
21640            expect(text.getText()).toContain('guest');
21641            expect(valid.getText()).toContain('true');
21642          });
21643
21644          it('should be invalid if empty', function() {
21645            input.clear();
21646            input.sendKeys('');
21647
21648            expect(text.getText()).toEqual('text =');
21649            expect(valid.getText()).toContain('false');
21650          });
21651
21652          it('should be invalid if multi word', function() {
21653            input.clear();
21654            input.sendKeys('hello world');
21655
21656            expect(valid.getText()).toContain('false');
21657          });
21658        </file>
21659      </example>
21660   */
21661  'text': textInputType,
21662
21663
21664  /**
21665   * @ngdoc input
21666   * @name input[number]
21667   *
21668   * @description
21669   * Text input with number validation and transformation. Sets the `number` validation
21670   * error if not a valid number.
21671   *
21672   * @param {string} ngModel Assignable angular expression to data-bind to.
21673   * @param {string=} name Property name of the form under which the control is published.
21674   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21675   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21676   * @param {string=} required Sets `required` validation error key if the value is not entered.
21677   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21678   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21679   *    `required` when you want to data-bind to the `required` attribute.
21680   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21681   *    minlength.
21682   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21683   *    maxlength.
21684   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
21685   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
21686   *    patterns defined as scope expressions.
21687   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21688   *    interaction with the input element.
21689   *
21690   * @example
21691      <example name="number-input-directive" module="numberExample">
21692        <file name="index.html">
21693         <script>
21694           angular.module('numberExample', [])
21695             .controller('ExampleController', ['$scope', function($scope) {
21696               $scope.value = 12;
21697             }]);
21698         </script>
21699         <form name="myForm" ng-controller="ExampleController">
21700           Number: <input type="number" name="input" ng-model="value"
21701                          min="0" max="99" required>
21702           <span class="error" ng-show="myForm.input.$error.required">
21703             Required!</span>
21704           <span class="error" ng-show="myForm.input.$error.number">
21705             Not valid number!</span>
21706           <tt>value = {{value}}</tt><br/>
21707           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21708           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21709           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21710           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21711          </form>
21712        </file>
21713        <file name="protractor.js" type="protractor">
21714          var value = element(by.binding('value'));
21715          var valid = element(by.binding('myForm.input.$valid'));
21716          var input = element(by.model('value'));
21717
21718          it('should initialize to model', function() {
21719            expect(value.getText()).toContain('12');
21720            expect(valid.getText()).toContain('true');
21721          });
21722
21723          it('should be invalid if empty', function() {
21724            input.clear();
21725            input.sendKeys('');
21726            expect(value.getText()).toEqual('value =');
21727            expect(valid.getText()).toContain('false');
21728          });
21729
21730          it('should be invalid if over max', function() {
21731            input.clear();
21732            input.sendKeys('123');
21733            expect(value.getText()).toEqual('value =');
21734            expect(valid.getText()).toContain('false');
21735          });
21736        </file>
21737      </example>
21738   */
21739  'number': numberInputType,
21740
21741
21742  /**
21743   * @ngdoc input
21744   * @name input[url]
21745   *
21746   * @description
21747   * Text input with URL validation. Sets the `url` validation error key if the content is not a
21748   * valid URL.
21749   *
21750   * @param {string} ngModel Assignable angular expression to data-bind to.
21751   * @param {string=} name Property name of the form under which the control is published.
21752   * @param {string=} required Sets `required` validation error key if the value is not entered.
21753   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21754   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21755   *    `required` when you want to data-bind to the `required` attribute.
21756   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21757   *    minlength.
21758   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21759   *    maxlength.
21760   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
21761   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
21762   *    patterns defined as scope expressions.
21763   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21764   *    interaction with the input element.
21765   *
21766   * @example
21767      <example name="url-input-directive" module="urlExample">
21768        <file name="index.html">
21769         <script>
21770           angular.module('urlExample', [])
21771             .controller('ExampleController', ['$scope', function($scope) {
21772               $scope.text = 'http://google.com';
21773             }]);
21774         </script>
21775         <form name="myForm" ng-controller="ExampleController">
21776           URL: <input type="url" name="input" ng-model="text" required>
21777           <span class="error" ng-show="myForm.input.$error.required">
21778             Required!</span>
21779           <span class="error" ng-show="myForm.input.$error.url">
21780             Not valid url!</span>
21781           <tt>text = {{text}}</tt><br/>
21782           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21783           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21784           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21785           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21786           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
21787          </form>
21788        </file>
21789        <file name="protractor.js" type="protractor">
21790          var text = element(by.binding('text'));
21791          var valid = element(by.binding('myForm.input.$valid'));
21792          var input = element(by.model('text'));
21793
21794          it('should initialize to model', function() {
21795            expect(text.getText()).toContain('http://google.com');
21796            expect(valid.getText()).toContain('true');
21797          });
21798
21799          it('should be invalid if empty', function() {
21800            input.clear();
21801            input.sendKeys('');
21802
21803            expect(text.getText()).toEqual('text =');
21804            expect(valid.getText()).toContain('false');
21805          });
21806
21807          it('should be invalid if not url', function() {
21808            input.clear();
21809            input.sendKeys('box');
21810
21811            expect(valid.getText()).toContain('false');
21812          });
21813        </file>
21814      </example>
21815   */
21816  'url': urlInputType,
21817
21818
21819  /**
21820   * @ngdoc input
21821   * @name input[email]
21822   *
21823   * @description
21824   * Text input with email validation. Sets the `email` validation error key if not a valid email
21825   * address.
21826   *
21827   * @param {string} ngModel Assignable angular expression to data-bind to.
21828   * @param {string=} name Property name of the form under which the control is published.
21829   * @param {string=} required Sets `required` validation error key if the value is not entered.
21830   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21831   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21832   *    `required` when you want to data-bind to the `required` attribute.
21833   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21834   *    minlength.
21835   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21836   *    maxlength.
21837   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
21838   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
21839   *    patterns defined as scope expressions.
21840   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21841   *    interaction with the input element.
21842   *
21843   * @example
21844      <example name="email-input-directive" module="emailExample">
21845        <file name="index.html">
21846         <script>
21847           angular.module('emailExample', [])
21848             .controller('ExampleController', ['$scope', function($scope) {
21849               $scope.text = '[email protected]';
21850             }]);
21851         </script>
21852           <form name="myForm" ng-controller="ExampleController">
21853             Email: <input type="email" name="input" ng-model="text" required>
21854             <span class="error" ng-show="myForm.input.$error.required">
21855               Required!</span>
21856             <span class="error" ng-show="myForm.input.$error.email">
21857               Not valid email!</span>
21858             <tt>text = {{text}}</tt><br/>
21859             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21860             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21861             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21862             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21863             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
21864           </form>
21865         </file>
21866        <file name="protractor.js" type="protractor">
21867          var text = element(by.binding('text'));
21868          var valid = element(by.binding('myForm.input.$valid'));
21869          var input = element(by.model('text'));
21870
21871          it('should initialize to model', function() {
21872            expect(text.getText()).toContain('[email protected]');
21873            expect(valid.getText()).toContain('true');
21874          });
21875
21876          it('should be invalid if empty', function() {
21877            input.clear();
21878            input.sendKeys('');
21879            expect(text.getText()).toEqual('text =');
21880            expect(valid.getText()).toContain('false');
21881          });
21882
21883          it('should be invalid if not email', function() {
21884            input.clear();
21885            input.sendKeys('xxx');
21886
21887            expect(valid.getText()).toContain('false');
21888          });
21889        </file>
21890      </example>
21891   */
21892  'email': emailInputType,
21893
21894
21895  /**
21896   * @ngdoc input
21897   * @name input[radio]
21898   *
21899   * @description
21900   * HTML radio button.
21901   *
21902   * @param {string} ngModel Assignable angular expression to data-bind to.
21903   * @param {string} value The value to which the expression should be set when selected.
21904   * @param {string=} name Property name of the form under which the control is published.
21905   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21906   *    interaction with the input element.
21907   * @param {string} ngValue Angular expression which sets the value to which the expression should
21908   *    be set when selected.
21909   *
21910   * @example
21911      <example name="radio-input-directive" module="radioExample">
21912        <file name="index.html">
21913         <script>
21914           angular.module('radioExample', [])
21915             .controller('ExampleController', ['$scope', function($scope) {
21916               $scope.color = 'blue';
21917               $scope.specialValue = {
21918                 "id": "12345",
21919                 "value": "green"
21920               };
21921             }]);
21922         </script>
21923         <form name="myForm" ng-controller="ExampleController">
21924           <input type="radio" ng-model="color" value="red">  Red <br/>
21925           <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
21926           <input type="radio" ng-model="color" value="blue"> Blue <br/>
21927           <tt>color = {{color | json}}</tt><br/>
21928          </form>
21929          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
21930        </file>
21931        <file name="protractor.js" type="protractor">
21932          it('should change state', function() {
21933            var color = element(by.binding('color'));
21934
21935            expect(color.getText()).toContain('blue');
21936
21937            element.all(by.model('color')).get(0).click();
21938
21939            expect(color.getText()).toContain('red');
21940          });
21941        </file>
21942      </example>
21943   */
21944  'radio': radioInputType,
21945
21946
21947  /**
21948   * @ngdoc input
21949   * @name input[checkbox]
21950   *
21951   * @description
21952   * HTML checkbox.
21953   *
21954   * @param {string} ngModel Assignable angular expression to data-bind to.
21955   * @param {string=} name Property name of the form under which the control is published.
21956   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
21957   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
21958   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21959   *    interaction with the input element.
21960   *
21961   * @example
21962      <example name="checkbox-input-directive" module="checkboxExample">
21963        <file name="index.html">
21964         <script>
21965           angular.module('checkboxExample', [])
21966             .controller('ExampleController', ['$scope', function($scope) {
21967               $scope.value1 = true;
21968               $scope.value2 = 'YES'
21969             }]);
21970         </script>
21971         <form name="myForm" ng-controller="ExampleController">
21972           Value1: <input type="checkbox" ng-model="value1"> <br/>
21973           Value2: <input type="checkbox" ng-model="value2"
21974                          ng-true-value="YES" ng-false-value="NO"> <br/>
21975           <tt>value1 = {{value1}}</tt><br/>
21976           <tt>value2 = {{value2}}</tt><br/>
21977          </form>
21978        </file>
21979        <file name="protractor.js" type="protractor">
21980          it('should change state', function() {
21981            var value1 = element(by.binding('value1'));
21982            var value2 = element(by.binding('value2'));
21983
21984            expect(value1.getText()).toContain('true');
21985            expect(value2.getText()).toContain('YES');
21986
21987            element(by.model('value1')).click();
21988            element(by.model('value2')).click();
21989
21990            expect(value1.getText()).toContain('false');
21991            expect(value2.getText()).toContain('NO');
21992          });
21993        </file>
21994      </example>
21995   */
21996  'checkbox': checkboxInputType,
21997
21998  'hidden': noop,
21999  'button': noop,
22000  'submit': noop,
22001  'reset': noop,
22002  'file': noop
22003};
22004
22005// A helper function to call $setValidity and return the value / undefined,
22006// a pattern that is repeated a lot in the input validation logic.
22007function validate(ctrl, validatorName, validity, value){
22008  ctrl.$setValidity(validatorName, validity);
22009  return validity ? value : undefined;
22010}
22011
22012function testFlags(validity, flags) {
22013  var i, flag;
22014  if (flags) {
22015    for (i=0; i<flags.length; ++i) {
22016      flag = flags[i];
22017      if (validity[flag]) {
22018        return true;
22019      }
22020    }
22021  }
22022  return false;
22023}
22024
22025// Pass validity so that behaviour can be mocked easier.
22026function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
22027  if (isObject(validity)) {
22028    ctrl.$$hasNativeValidators = true;
22029    var validator = function(value) {
22030      // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
22031      // perform the required validation)
22032      if (!ctrl.$error[validatorName] &&
22033          !testFlags(validity, ignoreFlags) &&
22034          testFlags(validity, badFlags)) {
22035        ctrl.$setValidity(validatorName, false);
22036        return;
22037      }
22038      return value;
22039    };
22040    ctrl.$parsers.push(validator);
22041  }
22042}
22043
22044function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22045  var validity = element.prop(VALIDITY_STATE_PROPERTY);
22046  var placeholder = element[0].placeholder, noevent = {};
22047  var type = lowercase(element[0].type);
22048  ctrl.$$validityState = validity;
22049
22050  // In composition mode, users are still inputing intermediate text buffer,
22051  // hold the listener until composition is done.
22052  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
22053  if (!$sniffer.android) {
22054    var composing = false;
22055
22056    element.on('compositionstart', function(data) {
22057      composing = true;
22058    });
22059
22060    element.on('compositionend', function() {
22061      composing = false;
22062      listener();
22063    });
22064  }
22065
22066  var listener = function(ev) {
22067    if (composing) return;
22068    var value = element.val();
22069
22070    // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
22071    // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
22072    // IE also sends input events for other non-input-related things, (such as focusing on a
22073    // form control), so this change is not entirely enough to solve this.
22074    if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
22075      placeholder = element[0].placeholder;
22076      return;
22077    }
22078
22079    // By default we will trim the value
22080    // If the attribute ng-trim exists we will avoid trimming
22081    // If input type is 'password', the value is never trimmed
22082    if (type !== 'password' && (toBoolean(attr.ngTrim || 'T'))) {
22083      value = trim(value);
22084    }
22085
22086    // If a control is suffering from bad input, browsers discard its value, so it may be
22087    // necessary to revalidate even if the control's value is the same empty value twice in
22088    // a row.
22089    var revalidate = validity && ctrl.$$hasNativeValidators;
22090    if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
22091      if (scope.$root.$$phase) {
22092        ctrl.$setViewValue(value);
22093      } else {
22094        scope.$apply(function() {
22095          ctrl.$setViewValue(value);
22096        });
22097      }
22098    }
22099  };
22100
22101  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
22102  // input event on backspace, delete or cut
22103  if ($sniffer.hasEvent('input')) {
22104    element.on('input', listener);
22105  } else {
22106    var timeout;
22107
22108    var deferListener = function() {
22109      if (!timeout) {
22110        timeout = $browser.defer(function() {
22111          listener();
22112          timeout = null;
22113        });
22114      }
22115    };
22116
22117    element.on('keydown', function(event) {
22118      var key = event.keyCode;
22119
22120      // ignore
22121      //    command            modifiers                   arrows
22122      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
22123
22124      deferListener();
22125    });
22126
22127    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
22128    if ($sniffer.hasEvent('paste')) {
22129      element.on('paste cut', deferListener);
22130    }
22131  }
22132
22133  // if user paste into input using mouse on older browser
22134  // or form autocomplete on newer browser, we need "change" event to catch it
22135  element.on('change', listener);
22136
22137  ctrl.$render = function() {
22138    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
22139  };
22140
22141  // pattern validator
22142  var pattern = attr.ngPattern,
22143      patternValidator,
22144      match;
22145
22146  if (pattern) {
22147    var validateRegex = function(regexp, value) {
22148      return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
22149    };
22150    match = pattern.match(/^\/(.*)\/([gim]*)$/);
22151    if (match) {
22152      pattern = new RegExp(match[1], match[2]);
22153      patternValidator = function(value) {
22154        return validateRegex(pattern, value);
22155      };
22156    } else {
22157      patternValidator = function(value) {
22158        var patternObj = scope.$eval(pattern);
22159
22160        if (!patternObj || !patternObj.test) {
22161          throw minErr('ngPattern')('noregexp',
22162            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
22163            patternObj, startingTag(element));
22164        }
22165        return validateRegex(patternObj, value);
22166      };
22167    }
22168
22169    ctrl.$formatters.push(patternValidator);
22170    ctrl.$parsers.push(patternValidator);
22171  }
22172
22173  // min length validator
22174  if (attr.ngMinlength) {
22175    var minlength = int(attr.ngMinlength);
22176    var minLengthValidator = function(value) {
22177      return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
22178    };
22179
22180    ctrl.$parsers.push(minLengthValidator);
22181    ctrl.$formatters.push(minLengthValidator);
22182  }
22183
22184  // max length validator
22185  if (attr.ngMaxlength) {
22186    var maxlength = int(attr.ngMaxlength);
22187    var maxLengthValidator = function(value) {
22188      return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
22189    };
22190
22191    ctrl.$parsers.push(maxLengthValidator);
22192    ctrl.$formatters.push(maxLengthValidator);
22193  }
22194}
22195
22196var numberBadFlags = ['badInput'];
22197
22198function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22199  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
22200
22201  ctrl.$parsers.push(function(value) {
22202    var empty = ctrl.$isEmpty(value);
22203    if (empty || NUMBER_REGEXP.test(value)) {
22204      ctrl.$setValidity('number', true);
22205      return value === '' ? null : (empty ? value : parseFloat(value));
22206    } else {
22207      ctrl.$setValidity('number', false);
22208      return undefined;
22209    }
22210  });
22211
22212  addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
22213
22214  ctrl.$formatters.push(function(value) {
22215    return ctrl.$isEmpty(value) ? '' : '' + value;
22216  });
22217
22218  if (attr.min) {
22219    var minValidator = function(value) {
22220      var min = parseFloat(attr.min);
22221      return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
22222    };
22223
22224    ctrl.$parsers.push(minValidator);
22225    ctrl.$formatters.push(minValidator);
22226  }
22227
22228  if (attr.max) {
22229    var maxValidator = function(value) {
22230      var max = parseFloat(attr.max);
22231      return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
22232    };
22233
22234    ctrl.$parsers.push(maxValidator);
22235    ctrl.$formatters.push(maxValidator);
22236  }
22237
22238  ctrl.$formatters.push(function(value) {
22239    return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
22240  });
22241}
22242
22243function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22244  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
22245
22246  var urlValidator = function(value) {
22247    return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
22248  };
22249
22250  ctrl.$formatters.push(urlValidator);
22251  ctrl.$parsers.push(urlValidator);
22252}
22253
22254function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22255  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
22256
22257  var emailValidator = function(value) {
22258    return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
22259  };
22260
22261  ctrl.$formatters.push(emailValidator);
22262  ctrl.$parsers.push(emailValidator);
22263}
22264
22265function radioInputType(scope, element, attr, ctrl) {
22266  // make the name unique, if not defined
22267  if (isUndefined(attr.name)) {
22268    element.attr('name', nextUid());
22269  }
22270
22271  element.on('click', function() {
22272    if (element[0].checked) {
22273      scope.$apply(function() {
22274        ctrl.$setViewValue(attr.value);
22275      });
22276    }
22277  });
22278
22279  ctrl.$render = function() {
22280    var value = attr.value;
22281    element[0].checked = (value == ctrl.$viewValue);
22282  };
22283
22284  attr.$observe('value', ctrl.$render);
22285}
22286
22287function checkboxInputType(scope, element, attr, ctrl) {
22288  var trueValue = attr.ngTrueValue,
22289      falseValue = attr.ngFalseValue;
22290
22291  if (!isString(trueValue)) trueValue = true;
22292  if (!isString(falseValue)) falseValue = false;
22293
22294  element.on('click', function() {
22295    scope.$apply(function() {
22296      ctrl.$setViewValue(element[0].checked);
22297    });
22298  });
22299
22300  ctrl.$render = function() {
22301    element[0].checked = ctrl.$viewValue;
22302  };
22303
22304  // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
22305  ctrl.$isEmpty = function(value) {
22306    return value !== trueValue;
22307  };
22308
22309  ctrl.$formatters.push(function(value) {
22310    return value === trueValue;
22311  });
22312
22313  ctrl.$parsers.push(function(value) {
22314    return value ? trueValue : falseValue;
22315  });
22316}
22317
22318
22319/**
22320 * @ngdoc directive
22321 * @name textarea
22322 * @restrict E
22323 *
22324 * @description
22325 * HTML textarea element control with angular data-binding. The data-binding and validation
22326 * properties of this element are exactly the same as those of the
22327 * {@link ng.directive:input input element}.
22328 *
22329 * @param {string} ngModel Assignable angular expression to data-bind to.
22330 * @param {string=} name Property name of the form under which the control is published.
22331 * @param {string=} required Sets `required` validation error key if the value is not entered.
22332 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
22333 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
22334 *    `required` when you want to data-bind to the `required` attribute.
22335 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22336 *    minlength.
22337 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22338 *    maxlength.
22339 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
22340 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
22341 *    patterns defined as scope expressions.
22342 * @param {string=} ngChange Angular expression to be executed when input changes due to user
22343 *    interaction with the input element.
22344 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22345 */
22346
22347
22348/**
22349 * @ngdoc directive
22350 * @name input
22351 * @restrict E
22352 *
22353 * @description
22354 * HTML input element control with angular data-binding. Input control follows HTML5 input types
22355 * and polyfills the HTML5 validation behavior for older browsers.
22356 *
22357 * *NOTE* Not every feature offered is available for all input types.
22358 *
22359 * @param {string} ngModel Assignable angular expression to data-bind to.
22360 * @param {string=} name Property name of the form under which the control is published.
22361 * @param {string=} required Sets `required` validation error key if the value is not entered.
22362 * @param {boolean=} ngRequired Sets `required` attribute if set to true
22363 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22364 *    minlength.
22365 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22366 *    maxlength.
22367 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
22368 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
22369 *    patterns defined as scope expressions.
22370 * @param {string=} ngChange Angular expression to be executed when input changes due to user
22371 *    interaction with the input element.
22372 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22373 *    This parameter is ignored for input[type=password] controls, which will never trim the
22374 *    input.
22375 *
22376 * @example
22377    <example name="input-directive" module="inputExample">
22378      <file name="index.html">
22379       <script>
22380          angular.module('inputExample', [])
22381            .controller('ExampleController', ['$scope', function($scope) {
22382              $scope.user = {name: 'guest', last: 'visitor'};
22383            }]);
22384       </script>
22385       <div ng-controller="ExampleController">
22386         <form name="myForm">
22387           User name: <input type="text" name="userName" ng-model="user.name" required>
22388           <span class="error" ng-show="myForm.userName.$error.required">
22389             Required!</span><br>
22390           Last name: <input type="text" name="lastName" ng-model="user.last"
22391             ng-minlength="3" ng-maxlength="10">
22392           <span class="error" ng-show="myForm.lastName.$error.minlength">
22393             Too short!</span>
22394           <span class="error" ng-show="myForm.lastName.$error.maxlength">
22395             Too long!</span><br>
22396         </form>
22397         <hr>
22398         <tt>user = {{user}}</tt><br/>
22399         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
22400         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
22401         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
22402         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
22403         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
22404         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
22405         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
22406         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
22407       </div>
22408      </file>
22409      <file name="protractor.js" type="protractor">
22410        var user = element(by.binding('{{user}}'));
22411        var userNameValid = element(by.binding('myForm.userName.$valid'));
22412        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
22413        var lastNameError = element(by.binding('myForm.lastName.$error'));
22414        var formValid = element(by.binding('myForm.$valid'));
22415        var userNameInput = element(by.model('user.name'));
22416        var userLastInput = element(by.model('user.last'));
22417
22418        it('should initialize to model', function() {
22419          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
22420          expect(userNameValid.getText()).toContain('true');
22421          expect(formValid.getText()).toContain('true');
22422        });
22423
22424        it('should be invalid if empty when required', function() {
22425          userNameInput.clear();
22426          userNameInput.sendKeys('');
22427
22428          expect(user.getText()).toContain('{"last":"visitor"}');
22429          expect(userNameValid.getText()).toContain('false');
22430          expect(formValid.getText()).toContain('false');
22431        });
22432
22433        it('should be valid if empty when min length is set', function() {
22434          userLastInput.clear();
22435          userLastInput.sendKeys('');
22436
22437          expect(user.getText()).toContain('{"name":"guest","last":""}');
22438          expect(lastNameValid.getText()).toContain('true');
22439          expect(formValid.getText()).toContain('true');
22440        });
22441
22442        it('should be invalid if less than required min length', function() {
22443          userLastInput.clear();
22444          userLastInput.sendKeys('xx');
22445
22446          expect(user.getText()).toContain('{"name":"guest"}');
22447          expect(lastNameValid.getText()).toContain('false');
22448          expect(lastNameError.getText()).toContain('minlength');
22449          expect(formValid.getText()).toContain('false');
22450        });
22451
22452        it('should be invalid if longer than max length', function() {
22453          userLastInput.clear();
22454          userLastInput.sendKeys('some ridiculously long name');
22455
22456          expect(user.getText()).toContain('{"name":"guest"}');
22457          expect(lastNameValid.getText()).toContain('false');
22458          expect(lastNameError.getText()).toContain('maxlength');
22459          expect(formValid.getText()).toContain('false');
22460        });
22461      </file>
22462    </example>
22463 */
22464var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
22465  return {
22466    restrict: 'E',
22467    require: '?ngModel',
22468    link: function(scope, element, attr, ctrl) {
22469      if (ctrl) {
22470        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
22471                                                            $browser);
22472      }
22473    }
22474  };
22475}];
22476
22477var VALID_CLASS = 'ng-valid',
22478    INVALID_CLASS = 'ng-invalid',
22479    PRISTINE_CLASS = 'ng-pristine',
22480    DIRTY_CLASS = 'ng-dirty';
22481
22482/**
22483 * @ngdoc type
22484 * @name ngModel.NgModelController
22485 *
22486 * @property {string} $viewValue Actual string value in the view.
22487 * @property {*} $modelValue The value in the model, that the control is bound to.
22488 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
22489       the control reads value from the DOM.  Each function is called, in turn, passing the value
22490       through to the next. The last return value is used to populate the model.
22491       Used to sanitize / convert the value as well as validation. For validation,
22492       the parsers should update the validity state using
22493       {@link ngModel.NgModelController#$setValidity $setValidity()},
22494       and return `undefined` for invalid values.
22495
22496 *
22497 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
22498       the model value changes. Each function is called, in turn, passing the value through to the
22499       next. Used to format / convert values for display in the control and validation.
22500 * ```js
22501 * function formatter(value) {
22502 *   if (value) {
22503 *     return value.toUpperCase();
22504 *   }
22505 * }
22506 * ngModel.$formatters.push(formatter);
22507 * ```
22508 *
22509 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
22510 *     view value has changed. It is called with no arguments, and its return value is ignored.
22511 *     This can be used in place of additional $watches against the model value.
22512 *
22513 * @property {Object} $error An object hash with all errors as keys.
22514 *
22515 * @property {boolean} $pristine True if user has not interacted with the control yet.
22516 * @property {boolean} $dirty True if user has already interacted with the control.
22517 * @property {boolean} $valid True if there is no error.
22518 * @property {boolean} $invalid True if at least one error on the control.
22519 *
22520 * @description
22521 *
22522 * `NgModelController` provides API for the `ng-model` directive. The controller contains
22523 * services for data-binding, validation, CSS updates, and value formatting and parsing. It
22524 * purposefully does not contain any logic which deals with DOM rendering or listening to
22525 * DOM events. Such DOM related logic should be provided by other directives which make use of
22526 * `NgModelController` for data-binding.
22527 *
22528 * ## Custom Control Example
22529 * This example shows how to use `NgModelController` with a custom control to achieve
22530 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
22531 * collaborate together to achieve the desired result.
22532 *
22533 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
22534 * contents be edited in place by the user.  This will not work on older browsers.
22535 *
22536 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
22537 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
22538 * However, as we are using `$sce` the model can still decide to to provide unsafe content if it marks
22539 * that content using the `$sce` service.
22540 *
22541 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
22542    <file name="style.css">
22543      [contenteditable] {
22544        border: 1px solid black;
22545        background-color: white;
22546        min-height: 20px;
22547      }
22548
22549      .ng-invalid {
22550        border: 1px solid red;
22551      }
22552
22553    </file>
22554    <file name="script.js">
22555      angular.module('customControl', ['ngSanitize']).
22556        directive('contenteditable', ['$sce', function($sce) {
22557          return {
22558            restrict: 'A', // only activate on element attribute
22559            require: '?ngModel', // get a hold of NgModelController
22560            link: function(scope, element, attrs, ngModel) {
22561              if(!ngModel) return; // do nothing if no ng-model
22562
22563              // Specify how UI should be updated
22564              ngModel.$render = function() {
22565                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
22566              };
22567
22568              // Listen for change events to enable binding
22569              element.on('blur keyup change', function() {
22570                scope.$apply(read);
22571              });
22572              read(); // initialize
22573
22574              // Write data to the model
22575              function read() {
22576                var html = element.html();
22577                // When we clear the content editable the browser leaves a <br> behind
22578                // If strip-br attribute is provided then we strip this out
22579                if( attrs.stripBr && html == '<br>' ) {
22580                  html = '';
22581                }
22582                ngModel.$setViewValue(html);
22583              }
22584            }
22585          };
22586        }]);
22587    </file>
22588    <file name="index.html">
22589      <form name="myForm">
22590       <div contenteditable
22591            name="myWidget" ng-model="userContent"
22592            strip-br="true"
22593            required>Change me!</div>
22594        <span ng-show="myForm.myWidget.$error.required">Required!</span>
22595       <hr>
22596       <textarea ng-model="userContent"></textarea>
22597      </form>
22598    </file>
22599    <file name="protractor.js" type="protractor">
22600    it('should data-bind and become invalid', function() {
22601      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
22602        // SafariDriver can't handle contenteditable
22603        // and Firefox driver can't clear contenteditables very well
22604        return;
22605      }
22606      var contentEditable = element(by.css('[contenteditable]'));
22607      var content = 'Change me!';
22608
22609      expect(contentEditable.getText()).toEqual(content);
22610
22611      contentEditable.clear();
22612      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
22613      expect(contentEditable.getText()).toEqual('');
22614      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
22615    });
22616    </file>
22617 * </example>
22618 *
22619 *
22620 */
22621var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate',
22622    function($scope, $exceptionHandler, $attr, $element, $parse, $animate) {
22623  this.$viewValue = Number.NaN;
22624  this.$modelValue = Number.NaN;
22625  this.$parsers = [];
22626  this.$formatters = [];
22627  this.$viewChangeListeners = [];
22628  this.$pristine = true;
22629  this.$dirty = false;
22630  this.$valid = true;
22631  this.$invalid = false;
22632  this.$name = $attr.name;
22633
22634  var ngModelGet = $parse($attr.ngModel),
22635      ngModelSet = ngModelGet.assign;
22636
22637  if (!ngModelSet) {
22638    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
22639        $attr.ngModel, startingTag($element));
22640  }
22641
22642  /**
22643   * @ngdoc method
22644   * @name ngModel.NgModelController#$render
22645   *
22646   * @description
22647   * Called when the view needs to be updated. It is expected that the user of the ng-model
22648   * directive will implement this method.
22649   */
22650  this.$render = noop;
22651
22652  /**
22653   * @ngdoc method
22654   * @name ngModel.NgModelController#$isEmpty
22655   *
22656   * @description
22657   * This is called when we need to determine if the value of the input is empty.
22658   *
22659   * For instance, the required directive does this to work out if the input has data or not.
22660   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
22661   *
22662   * You can override this for input directives whose concept of being empty is different to the
22663   * default. The `checkboxInputType` directive does this because in its case a value of `false`
22664   * implies empty.
22665   *
22666   * @param {*} value Reference to check.
22667   * @returns {boolean} True if `value` is empty.
22668   */
22669  this.$isEmpty = function(value) {
22670    return isUndefined(value) || value === '' || value === null || value !== value;
22671  };
22672
22673  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
22674      invalidCount = 0, // used to easily determine if we are valid
22675      $error = this.$error = {};
22675 // keep invalid keys here
22676
22677
22678  // Setup initial state of the control
22679  $element.addClass(PRISTINE_CLASS);
22680  toggleValidCss(true);
22681
22682  // convenience method for easy toggling of classes
22683  function toggleValidCss(isValid, validationErrorKey) {
22684    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
22685    $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
22686    $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
22687  }
22688
22689  /**
22690   * @ngdoc method
22691   * @name ngModel.NgModelController#$setValidity
22692   *
22693   * @description
22694   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
22695   * does not notify form if given validator is already marked as invalid).
22696   *
22697   * This method should be called by validators - i.e. the parser or formatter functions.
22698   *
22699   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
22700   *        to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
22701   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
22702   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
22703   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
22704   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
22705   */
22706  this.$setValidity = function(validationErrorKey, isValid) {
22707    // Purposeful use of ! here to cast isValid to boolean in case it is undefined
22708    // jshint -W018
22709    if ($error[validationErrorKey] === !isValid) return;
22710    // jshint +W018
22711
22712    if (isValid) {
22713      if ($error[validationErrorKey]) invalidCount--;
22714      if (!invalidCount) {
22715        toggleValidCss(true);
22716        this.$valid = true;
22717        this.$invalid = false;
22718      }
22719    } else {
22720      toggleValidCss(false);
22721      this.$invalid = true;
22722      this.$valid = false;
22723      invalidCount++;
22724    }
22725
22726    $error[validationErrorKey] = !isValid;
22727    toggleValidCss(isValid, validationErrorKey);
22728
22729    parentForm.$setValidity(validationErrorKey, isValid, this);
22730  };
22731
22732  /**
22733   * @ngdoc method
22734   * @name ngModel.NgModelController#$setPristine
22735   *
22736   * @description
22737   * Sets the control to its pristine state.
22738   *
22739   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
22740   * state (ng-pristine class).
22741   */
22742  this.$setPristine = function () {
22743    this.$dirty = false;
22744    this.$pristine = true;
22745    $animate.removeClass($element, DIRTY_CLASS);
22746    $animate.addClass($element, PRISTINE_CLASS);
22747  };
22748
22749  /**
22750   * @ngdoc method
22751   * @name ngModel.NgModelController#$setViewValue
22752   *
22753   * @description
22754   * Update the view value.
22755   *
22756   * This method should be called when the view value changes, typically from within a DOM event handler.
22757   * For example {@link ng.directive:input input} and
22758   * {@link ng.directive:select select} directives call it.
22759   *
22760   * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
22761   * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
22762   * `$modelValue` and the **expression** specified in the `ng-model` attribute.
22763   *
22764   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
22765   *
22766   * Note that calling this function does not trigger a `$digest`.
22767   *
22768   * @param {string} value Value from the view.
22769   */
22770  this.$setViewValue = function(value) {
22771    this.$viewValue = value;
22772
22773    // change to dirty
22774    if (this.$pristine) {
22775      this.$dirty = true;
22776      this.$pristine = false;
22777      $animate.removeClass($element, PRISTINE_CLASS);
22778      $animate.addClass($element, DIRTY_CLASS);
22779      parentForm.$setDirty();
22780    }
22781
22782    forEach(this.$parsers, function(fn) {
22783      value = fn(value);
22784    });
22785
22786    if (this.$modelValue !== value) {
22787      this.$modelValue = value;
22788      ngModelSet($scope, value);
22789      forEach(this.$viewChangeListeners, function(listener) {
22790        try {
22791          listener();
22792        } catch(e) {
22793          $exceptionHandler(e);
22794        }
22795      });
22796    }
22797  };
22798
22799  // model -> value
22800  var ctrl = this;
22801
22802  $scope.$watch(function ngModelWatch() {
22803    var value = ngModelGet($scope);
22804
22805    // if scope model value and ngModel value are out of sync
22806    if (ctrl.$modelValue !== value) {
22807
22808      var formatters = ctrl.$formatters,
22809          idx = formatters.length;
22810
22811      ctrl.$modelValue = value;
22812      while(idx--) {
22813        value = formatters[idx](value);
22814      }
22815
22816      if (ctrl.$viewValue !== value) {
22817        ctrl.$viewValue = value;
22818        ctrl.$render();
22819      }
22820    }
22821
22822    return value;
22823  });
22824}];
22825
22826
22827/**
22828 * @ngdoc directive
22829 * @name ngModel
22830 *
22831 * @element input
22832 *
22833 * @description
22834 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
22835 * property on the scope using {@link ngModel.NgModelController NgModelController},
22836 * which is created and exposed by this directive.
22837 *
22838 * `ngModel` is responsible for:
22839 *
22840 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
22841 *   require.
22842 * - Providing validation behavior (i.e. required, number, email, url).
22843 * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
22844 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
22845 * - Registering the control with its parent {@link ng.directive:form form}.
22846 *
22847 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
22848 * current scope. If the property doesn't already exist on this scope, it will be created
22849 * implicitly and added to the scope.
22850 *
22851 * For best practices on using `ngModel`, see:
22852 *
22853 *  - [https://github.com/angular/angular.js/wiki/Understanding-Scopes]
22854 *
22855 * For basic examples, how to use `ngModel`, see:
22856 *
22857 *  - {@link ng.directive:input input}
22858 *    - {@link input[text] text}
22859 *    - {@link input[checkbox] checkbox}
22860 *    - {@link input[radio] radio}
22861 *    - {@link input[number] number}
22862 *    - {@link input[email] email}
22863 *    - {@link input[url] url}
22864 *  - {@link ng.directive:select select}
22865 *  - {@link ng.directive:textarea textarea}
22866 *
22867 * # CSS classes
22868 * The following CSS classes are added and removed on the associated input/select/textarea element
22869 * depending on the validity of the model.
22870 *
22871 *  - `ng-valid` is set if the model is valid.
22872 *  - `ng-invalid` is set if the model is invalid.
22873 *  - `ng-pristine` is set if the model is pristine.
22874 *  - `ng-dirty` is set if the model is dirty.
22875 *
22876 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
22877 *
22878 * ## Animation Hooks
22879 *
22880 * Animations within models are triggered when any of the associated CSS classes are added and removed
22881 * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
22882 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
22883 * The animations that are triggered within ngModel are similar to how they work in ngClass and
22884 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
22885 *
22886 * The following example shows a simple way to utilize CSS transitions to style an input element
22887 * that has been rendered as invalid after it has been validated:
22888 *
22889 * <pre>
22890 * //be sure to include ngAnimate as a module to hook into more
22891 * //advanced animations
22892 * .my-input {
22893 *   transition:0.5s linear all;
22894 *   background: white;
22895 * }
22896 * .my-input.ng-invalid {
22897 *   background: red;
22898 *   color:white;
22899 * }
22900 * </pre>
22901 *
22902 * @example
22903 * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
22904     <file name="index.html">
22905       <script>
22906        angular.module('inputExample', [])
22907          .controller('ExampleController', ['$scope', function($scope) {
22908            $scope.val = '1';
22909          }]);
22910       </script>
22911       <style>
22912         .my-input {
22913           -webkit-transition:all linear 0.5s;
22914           transition:all linear 0.5s;
22915           background: transparent;
22916         }
22917         .my-input.ng-invalid {
22918           color:white;
22919           background: red;
22920         }
22921       </style>
22922       Update input to see transitions when valid/invalid.
22923       Integer is a valid value.
22924       <form name="testForm" ng-controller="ExampleController">
22925         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
22926       </form>
22927     </file>
22928 * </example>
22929 */
22930var ngModelDirective = function() {
22931  return {
22932    require: ['ngModel', '^?form'],
22933    controller: NgModelController,
22934    link: function(scope, element, attr, ctrls) {
22935      // notify others, especially parent forms
22936
22937      var modelCtrl = ctrls[0],
22938          formCtrl = ctrls[1] || nullFormCtrl;
22939
22940      formCtrl.$addControl(modelCtrl);
22941
22942      scope.$on('$destroy', function() {
22943        formCtrl.$removeControl(modelCtrl);
22944      });
22945    }
22946  };
22947};
22948
22949
22950/**
22951 * @ngdoc directive
22952 * @name ngChange
22953 *
22954 * @description
22955 * Evaluate the given expression when the user changes the input.
22956 * The expression is evaluated immediately, unlike the JavaScript onchange event
22957 * which only triggers at the end of a change (usually, when the user leaves the
22958 * form element or presses the return key).
22959 * The expression is not evaluated when the value change is coming from the model.
22960 *
22961 * Note, this directive requires `ngModel` to be present.
22962 *
22963 * @element input
22964 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
22965 * in input value.
22966 *
22967 * @example
22968 * <example name="ngChange-directive" module="changeExample">
22969 *   <file name="index.html">
22970 *     <script>
22971 *       angular.module('changeExample', [])
22972 *         .controller('ExampleController', ['$scope', function($scope) {
22973 *           $scope.counter = 0;
22974 *           $scope.change = function() {
22975 *             $scope.counter++;
22976 *           };
22977 *         }]);
22978 *     </script>
22979 *     <div ng-controller="ExampleController">
22980 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
22981 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
22982 *       <label for="ng-change-example2">Confirmed</label><br />
22983 *       <tt>debug = {{confirmed}}</tt><br/>
22984 *       <tt>counter = {{counter}}</tt><br/>
22985 *     </div>
22986 *   </file>
22987 *   <file name="protractor.js" type="protractor">
22988 *     var counter = element(by.binding('counter'));
22989 *     var debug = element(by.binding('confirmed'));
22990 *
22991 *     it('should evaluate the expression if changing from view', function() {
22992 *       expect(counter.getText()).toContain('0');
22993 *
22994 *       element(by.id('ng-change-example1')).click();
22995 *
22996 *       expect(counter.getText()).toContain('1');
22997 *       expect(debug.getText()).toContain('true');
22998 *     });
22999 *
23000 *     it('should not evaluate the expression if changing from model', function() {
23001 *       element(by.id('ng-change-example2')).click();
23002
23003 *       expect(counter.getText()).toContain('0');
23004 *       expect(debug.getText()).toContain('true');
23005 *     });
23006 *   </file>
23007 * </example>
23008 */
23009var ngChangeDirective = valueFn({
23010  require: 'ngModel',
23011  link: function(scope, element, attr, ctrl) {
23012    ctrl.$viewChangeListeners.push(function() {
23013      scope.$eval(attr.ngChange);
23014    });
23015  }
23016});
23017
23018
23019var requiredDirective = function() {
23020  return {
23021    require: '?ngModel',
23022    link: function(scope, elm, attr, ctrl) {
23023      if (!ctrl) return;
23024      attr.required = true; // force truthy in case we are on non input element
23025
23026      var validator = function(value) {
23027        if (attr.required && ctrl.$isEmpty(value)) {
23028          ctrl.$setValidity('required', false);
23029          return;
23030        } else {
23031          ctrl.$setValidity('required', true);
23032          return value;
23033        }
23034      };
23035
23036      ctrl.$formatters.push(validator);
23037      ctrl.$parsers.unshift(validator);
23038
23039      attr.$observe('required', function() {
23040        validator(ctrl.$viewValue);
23041      });
23042    }
23043  };
23044};
23045
23046
23047/**
23048 * @ngdoc directive
23049 * @name ngList
23050 *
23051 * @description
23052 * Text input that converts between a delimited string and an array of strings. The delimiter
23053 * can be a fixed string (by default a comma) or a regular expression.
23054 *
23055 * @element input
23056 * @param {string=} ngList optional delimiter that should be used to split the value. If
23057 *   specified in form `/something/` then the value will be converted into a regular expression.
23058 *
23059 * @example
23060    <example name="ngList-directive" module="listExample">
23061      <file name="index.html">
23062       <script>
23063         angular.module('listExample', [])
23064           .controller('ExampleController', ['$scope', function($scope) {
23065             $scope.names = ['igor', 'misko', 'vojta'];
23066           }]);
23067       </script>
23068       <form name="myForm" ng-controller="ExampleController">
23069         List: <input name="namesInput" ng-model="names" ng-list required>
23070         <span class="error" ng-show="myForm.namesInput.$error.required">
23071           Required!</span>
23072         <br>
23073         <tt>names = {{names}}</tt><br/>
23074         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
23075         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
23076         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
23077         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
23078        </form>
23079      </file>
23080      <file name="protractor.js" type="protractor">
23081        var listInput = element(by.model('names'));
23082        var names = element(by.binding('{{names}}'));
23083        var valid = element(by.binding('myForm.namesInput.$valid'));
23084        var error = element(by.css('span.error'));
23085
23086        it('should initialize to model', function() {
23087          expect(names.getText()).toContain('["igor","misko","vojta"]');
23088          expect(valid.getText()).toContain('true');
23089          expect(error.getCssValue('display')).toBe('none');
23090        });
23091
23092        it('should be invalid if empty', function() {
23093          listInput.clear();
23094          listInput.sendKeys('');
23095
23096          expect(names.getText()).toContain('');
23097          expect(valid.getText()).toContain('false');
23098          expect(error.getCssValue('display')).not.toBe('none');        });
23099      </file>
23100    </example>
23101 */
23102var ngListDirective = function() {
23103  return {
23104    require: 'ngModel',
23105    link: function(scope, element, attr, ctrl) {
23106      var match = /\/(.*)\//.exec(attr.ngList),
23107          separator = match && new RegExp(match[1]) || attr.ngList || ',';
23108
23109      var parse = function(viewValue) {
23110        // If the viewValue is invalid (say required but empty) it will be `undefined`
23111        if (isUndefined(viewValue)) return;
23112
23113        var list = [];
23114
23115        if (viewValue) {
23116          forEach(viewValue.split(separator), function(value) {
23117            if (value) list.push(trim(value));
23118          });
23119        }
23120
23121        return list;
23122      };
23123
23124      ctrl.$parsers.push(parse);
23125      ctrl.$formatters.push(function(value) {
23126        if (isArray(value)) {
23127          return value.join(', ');
23128        }
23129
23130        return undefined;
23131      });
23132
23133      // Override the standard $isEmpty because an empty array means the input is empty.
23134      ctrl.$isEmpty = function(value) {
23135        return !value || !value.length;
23136      };
23137    }
23138  };
23139};
23140
23141
23142var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
23143/**
23144 * @ngdoc directive
23145 * @name ngValue
23146 *
23147 * @description
23148 * Binds the given expression to the value of `input[select]` or `input[radio]`, so
23149 * that when the element is selected, the `ngModel` of that element is set to the
23150 * bound value.
23151 *
23152 * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
23153 * shown below.
23154 *
23155 * @element input
23156 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
23157 *   of the `input` element
23158 *
23159 * @example
23160    <example name="ngValue-directive" module="valueExample">
23161      <file name="index.html">
23162       <script>
23163          angular.module('valueExample', [])
23164            .controller('ExampleController', ['$scope', function($scope) {
23165              $scope.names = ['pizza', 'unicorns', 'robots'];
23166              $scope.my = { favorite: 'unicorns' };
23167            }]);
23168       </script>
23169        <form ng-controller="ExampleController">
23170          <h2>Which is your favorite?</h2>
23171            <label ng-repeat="name in names" for="{{name}}">
23172              {{name}}
23173              <input type="radio"
23174                     ng-model="my.favorite"
23175                     ng-value="name"
23176                     id="{{name}}"
23177                     name="favorite">
23178            </label>
23179          <div>You chose {{my.favorite}}</div>
23180        </form>
23181      </file>
23182      <file name="protractor.js" type="protractor">
23183        var favorite = element(by.binding('my.favorite'));
23184
23185        it('should initialize to model', function() {
23186          expect(favorite.getText()).toContain('unicorns');
23187        });
23188        it('should bind the values to the inputs', function() {
23189          element.all(by.model('my.favorite')).get(0).click();
23190          expect(favorite.getText()).toContain('pizza');
23191        });
23192      </file>
23193    </example>
23194 */
23195var ngValueDirective = function() {
23196  return {
23197    priority: 100,
23198    compile: function(tpl, tplAttr) {
23199      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
23200        return function ngValueConstantLink(scope, elm, attr) {
23201          attr.$set('value', scope.$eval(attr.ngValue));
23202        };
23203      } else {
23204        return function ngValueLink(scope, elm, attr) {
23205          scope.$watch(attr.ngValue, function valueWatchAction(value) {
23206            attr.$set('value', value);
23207          });
23208        };
23209      }
23210    }
23211  };
23212};
23213
23214/**
23215 * @ngdoc directive
23216 * @name ngBind
23217 * @restrict AC
23218 *
23219 * @description
23220 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
23221 * with the value of a given expression, and to update the text content when the value of that
23222 * expression changes.
23223 *
23224 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
23225 * `{{ expression }}` which is similar but less verbose.
23226 *
23227 * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
23228 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
23229 * element attribute, it makes the bindings invisible to the user while the page is loading.
23230 *
23231 * An alternative solution to this problem would be using the
23232 * {@link ng.directive:ngCloak ngCloak} directive.
23233 *
23234 *
23235 * @element ANY
23236 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
23237 *
23238 * @example
23239 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
23240   <example module="bindExample">
23241     <file name="index.html">
23242       <script>
23243         angular.module('bindExample', [])
23244           .controller('ExampleController', ['$scope', function($scope) {
23245             $scope.name = 'Whirled';
23246           }]);
23247       </script>
23248       <div ng-controller="ExampleController">
23249         Enter name: <input type="text" ng-model="name"><br>
23250         Hello <span ng-bind="name"></span>!
23251       </div>
23252     </file>
23253     <file name="protractor.js" type="protractor">
23254       it('should check ng-bind', function() {
23255         var nameInput = element(by.model('name'));
23256
23257         expect(element(by.binding('name')).getText()).toBe('Whirled');
23258         nameInput.clear();
23259         nameInput.sendKeys('world');
23260         expect(element(by.binding('name')).getText()).toBe('world');
23261       });
23262     </file>
23263   </example>
23264 */
23265var ngBindDirective = ngDirective({
23266  compile: function(templateElement) {
23267    templateElement.addClass('ng-binding');
23268    return function (scope, element, attr) {
23269      element.data('$binding', attr.ngBind);
23270      scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
23271        // We are purposefully using == here rather than === because we want to
23272        // catch when value is "null or undefined"
23273        // jshint -W041
23274        element.text(value == undefined ? '' : value);
23275      });
23276    };
23277  }
23278});
23279
23280
23281/**
23282 * @ngdoc directive
23283 * @name ngBindTemplate
23284 *
23285 * @description
23286 * The `ngBindTemplate` directive specifies that the element
23287 * text content should be replaced with the interpolation of the template
23288 * in the `ngBindTemplate` attribute.
23289 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
23290 * expressions. This directive is needed since some HTML elements
23291 * (such as TITLE and OPTION) cannot contain SPAN elements.
23292 *
23293 * @element ANY
23294 * @param {string} ngBindTemplate template of form
23295 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
23296 *
23297 * @example
23298 * Try it here: enter text in text box and watch the greeting change.
23299   <example module="bindExample">
23300     <file name="index.html">
23301       <script>
23302         angular.module('bindExample', [])
23303           .controller('ExampleController', ['$scope', function ($scope) {
23304             $scope.salutation = 'Hello';
23305             $scope.name = 'World';
23306           }]);
23307       </script>
23308       <div ng-controller="ExampleController">
23309        Salutation: <input type="text" ng-model="salutation"><br>
23310        Name: <input type="text" ng-model="name"><br>
23311        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
23312       </div>
23313     </file>
23314     <file name="protractor.js" type="protractor">
23315       it('should check ng-bind', function() {
23316         var salutationElem = element(by.binding('salutation'));
23317         var salutationInput = element(by.model('salutation'));
23318         var nameInput = element(by.model('name'));
23319
23320         expect(salutationElem.getText()).toBe('Hello World!');
23321
23322         salutationInput.clear();
23323         salutationInput.sendKeys('Greetings');
23324         nameInput.clear();
23325         nameInput.sendKeys('user');
23326
23327         expect(salutationElem.getText()).toBe('Greetings user!');
23328       });
23329     </file>
23330   </example>
23331 */
23332var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
23333  return function(scope, element, attr) {
23334    // TODO: move this to scenario runner
23335    var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
23336    element.addClass('ng-binding').data('$binding', interpolateFn);
23337    attr.$observe('ngBindTemplate', function(value) {
23338      element.text(value);
23339    });
23340  };
23341}];
23342
23343
23344/**
23345 * @ngdoc directive
23346 * @name ngBindHtml
23347 *
23348 * @description
23349 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
23350 * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
23351 * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
23352 * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
23353 * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
23354 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
23355 * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
23356 *
23357 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
23358 * will have an exception (instead of an exploit.)
23359 *
23360 * @element ANY
23361 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
23362 *
23363 * @example
23364
23365   <example module="bindHtmlExample" deps="angular-sanitize.js">
23366     <file name="index.html">
23367       <div ng-controller="ExampleController">
23368        <p ng-bind-html="myHTML"></p>
23369       </div>
23370     </file>
23371
23372     <file name="script.js">
23373       angular.module('bindHtmlExample', ['ngSanitize'])
23374         .controller('ExampleController', ['$scope', function($scope) {
23375           $scope.myHTML =
23376              'I am an <code>HTML</code>string with ' +
23377              '<a href="#">links!</a> and other <em>stuff</em>';
23378         }]);
23379     </file>
23380
23381     <file name="protractor.js" type="protractor">
23382       it('should check ng-bind-html', function() {
23383         expect(element(by.binding('myHTML')).getText()).toBe(
23384             'I am an HTMLstring with links! and other stuff');
23385       });
23386     </file>
23387   </example>
23388 */
23389var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
23390  return {
23391    compile: function (tElement) {
23392      tElement.addClass('ng-binding');
23393
23394      return function (scope, element, attr) {
23395        element.data('$binding', attr.ngBindHtml);
23396
23397        var parsed = $parse(attr.ngBindHtml);
23398
23399        function getStringValue() {
23400          return (parsed(scope) || '').toString();
23401        }
23402
23403        scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
23404          element.html($sce.getTrustedHtml(parsed(scope)) || '');
23405        });
23406      };
23407    }
23408  };
23409}];
23410
23411function classDirective(name, selector) {
23412  name = 'ngClass' + name;
23413  return ['$animate', function($animate) {
23414    return {
23415      restrict: 'AC',
23416      link: function(scope, element, attr) {
23417        var oldVal;
23418
23419        scope.$watch(attr[name], ngClassWatchAction, true);
23420
23421        attr.$observe('class', function(value) {
23422          ngClassWatchAction(scope.$eval(attr[name]));
23423        });
23424
23425
23426        if (name !== 'ngClass') {
23427          scope.$watch('$index', function($index, old$index) {
23428            // jshint bitwise: false
23429            var mod = $index & 1;
23430            if (mod !== (old$index & 1)) {
23431              var classes = arrayClasses(scope.$eval(attr[name]));
23432              mod === selector ?
23433                addClasses(classes) :
23434                removeClasses(classes);
23435            }
23436          });
23437        }
23438
23439        function addClasses(classes) {
23440          var newClasses = digestClassCounts(classes, 1);
23441          attr.$addClass(newClasses);
23442        }
23443
23444        function removeClasses(classes) {
23445          var newClasses = digestClassCounts(classes, -1);
23446          attr.$removeClass(newClasses);
23447        }
23448
23449        function digestClassCounts (classes, count) {
23450          var classCounts = element.data('$classCounts') || {};
23451          var classesToUpdate = [];
23452          forEach(classes, function (className) {
23453            if (count > 0 || classCounts[className]) {
23454              classCounts[className] = (classCounts[className] || 0) + count;
23455              if (classCounts[className] === +(count > 0)) {
23456                classesToUpdate.push(className);
23457              }
23458            }
23459          });
23460          element.data('$classCounts', classCounts);
23461          return classesToUpdate.join(' ');
23462        }
23463
23464        function updateClasses (oldClasses, newClasses) {
23465          var toAdd = arrayDifference(newClasses, oldClasses);
23466          var toRemove = arrayDifference(oldClasses, newClasses);
23467          toRemove = digestClassCounts(toRemove, -1);
23468          toAdd = digestClassCounts(toAdd, 1);
23469
23470          if (toAdd.length === 0) {
23471            $animate.removeClass(element, toRemove);
23472          } else if (toRemove.length === 0) {
23473            $animate.addClass(element, toAdd);
23474          } else {
23475            $animate.setClass(element, toAdd, toRemove);
23476          }
23477        }
23478
23479        function ngClassWatchAction(newVal) {
23480          if (selector === true || scope.$index % 2 === selector) {
23481            var newClasses = arrayClasses(newVal || []);
23482            if (!oldVal) {
23483              addClasses(newClasses);
23484            } else if (!equals(newVal,oldVal)) {
23485              var oldClasses = arrayClasses(oldVal);
23486              updateClasses(oldClasses, newClasses);
23487            }
23488          }
23489          oldVal = shallowCopy(newVal);
23490        }
23491      }
23492    };
23493
23494    function arrayDifference(tokens1, tokens2) {
23495      var values = [];
23496
23497      outer:
23498      for(var i = 0; i < tokens1.length; i++) {
23499        var token = tokens1[i];
23500        for(var j = 0; j < tokens2.length; j++) {
23501          if(token == tokens2[j]) continue outer;
23502        }
23503        values.push(token);
23504      }
23505      return values;
23506    }
23507
23508    function arrayClasses (classVal) {
23509      if (isArray(classVal)) {
23510        return classVal;
23511      } else if (isString(classVal)) {
23512        return classVal.split(' ');
23513      } else if (isObject(classVal)) {
23514        var classes = [], i = 0;
23515        forEach(classVal, function(v, k) {
23516          if (v) {
23517            classes = classes.concat(k.split(' '));
23518          }
23519        });
23520        return classes;
23521      }
23522      return classVal;
23523    }
23524  }];
23525}
23526
23527/**
23528 * @ngdoc directive
23529 * @name ngClass
23530 * @restrict AC
23531 *
23532 * @description
23533 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
23534 * an expression that represents all classes to be added.
23535 *
23536 * The directive operates in three different ways, depending on which of three types the expression
23537 * evaluates to:
23538 *
23539 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
23540 * names.
23541 *
23542 * 2. If the expression evaluates to an array, each element of the array should be a string that is
23543 * one or more space-delimited class names.
23544 *
23545 * 3. If the expression evaluates to an object, then for each key-value pair of the
23546 * object with a truthy value the corresponding key is used as a class name.
23547 *
23548 * The directive won't add duplicate classes if a particular class was already set.
23549 *
23550 * When the expression changes, the previously added classes are removed and only then the
23551 * new classes are added.
23552 *
23553 * @animations
23554 * add - happens just before the class is applied to the element
23555 * remove - happens just before the class is removed from the element
23556 *
23557 * @element ANY
23558 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
23559 *   of the evaluation can be a string representing space delimited class
23560 *   names, an array, or a map of class names to boolean values. In the case of a map, the
23561 *   names of the properties whose values are truthy will be added as css classes to the
23562 *   element.
23563 *
23564 * @example Example that demonstrates basic bindings via ngClass directive.
23565   <example>
23566     <file name="index.html">
23567       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
23568       <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
23569       <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
23570       <input type="checkbox" ng-model="error"> error (apply "red" class)
23571       <hr>
23572       <p ng-class="style">Using String Syntax</p>
23573       <input type="text" ng-model="style" placeholder="Type: bold strike red">
23574       <hr>
23575       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
23576       <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
23577       <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
23578       <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
23579     </file>
23580     <file name="style.css">
23581       .strike {
23582         text-decoration: line-through;
23583       }
23584       .bold {
23585           font-weight: bold;
23586       }
23587       .red {
23588           color: red;
23589       }
23590     </file>
23591     <file name="protractor.js" type="protractor">
23592       var ps = element.all(by.css('p'));
23593
23594       it('should let you toggle the class', function() {
23595
23596         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
23597         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
23598
23599         element(by.model('important')).click();
23600         expect(ps.first().getAttribute('class')).toMatch(/bold/);
23601
23602         element(by.model('error')).click();
23603         expect(ps.first().getAttribute('class')).toMatch(/red/);
23604       });
23605
23606       it('should let you toggle string example', function() {
23607         expect(ps.get(1).getAttribute('class')).toBe('');
23608         element(by.model('style')).clear();
23609         element(by.model('style')).sendKeys('red');
23610         expect(ps.get(1).getAttribute('class')).toBe('red');
23611       });
23612
23613       it('array example should have 3 classes', function() {
23614         expect(ps.last().getAttribute('class')).toBe('');
23615         element(by.model('style1')).sendKeys('bold');
23616         element(by.model('style2')).sendKeys('strike');
23617         element(by.model('style3')).sendKeys('red');
23618         expect(ps.last().getAttribute('class')).toBe('bold strike red');
23619       });
23620     </file>
23621   </example>
23622
23623   ## Animations
23624
23625   The example below demonstrates how to perform animations using ngClass.
23626
23627   <example module="ngAnimate" deps="angular-animate.js" animations="true">
23628     <file name="index.html">
23629      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
23630      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
23631      <br>
23632      <span class="base-class" ng-class="myVar">Sample Text</span>
23633     </file>
23634     <file name="style.css">
23635       .base-class {
23636         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23637         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23638       }
23639
23640       .base-class.my-class {
23641         color: red;
23642         font-size:3em;
23643       }
23644     </file>
23645     <file name="protractor.js" type="protractor">
23646       it('should check ng-class', function() {
23647         expect(element(by.css('.base-class')).getAttribute('class')).not.
23648           toMatch(/my-class/);
23649
23650         element(by.id('setbtn')).click();
23651
23652         expect(element(by.css('.base-class')).getAttribute('class')).
23653           toMatch(/my-class/);
23654
23655         element(by.id('clearbtn')).click();
23656
23657         expect(element(by.css('.base-class')).getAttribute('class')).not.
23658           toMatch(/my-class/);
23659       });
23660     </file>
23661   </example>
23662
23663
23664   ## ngClass and pre-existing CSS3 Transitions/Animations
23665   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
23666   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
23667   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
23668   to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
23669   {@link ngAnimate.$animate#removeclass $animate.removeClass}.
23670 */
23671var ngClassDirective = classDirective('', true);
23672
23673/**
23674 * @ngdoc directive
23675 * @name ngClassOdd
23676 * @restrict AC
23677 *
23678 * @description
23679 * The `ngClassOdd` and `ngClassEven` directives work exactly as
23680 * {@link ng.directive:ngClass ngClass}, except they work in
23681 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23682 *
23683 * This directive can be applied only within the scope of an
23684 * {@link ng.directive:ngRepeat ngRepeat}.
23685 *
23686 * @element ANY
23687 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
23688 *   of the evaluation can be a string representing space delimited class names or an array.
23689 *
23690 * @example
23691   <example>
23692     <file name="index.html">
23693        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23694          <li ng-repeat="name in names">
23695           <span ng-class-odd="'odd'" ng-class-even="'even'">
23696             {{name}}
23697           </span>
23698          </li>
23699        </ol>
23700     </file>
23701     <file name="style.css">
23702       .odd {
23703         color: red;
23704       }
23705       .even {
23706         color: blue;
23707       }
23708     </file>
23709     <file name="protractor.js" type="protractor">
23710       it('should check ng-class-odd and ng-class-even', function() {
23711         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23712           toMatch(/odd/);
23713         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23714           toMatch(/even/);
23715       });
23716     </file>
23717   </example>
23718 */
23719var ngClassOddDirective = classDirective('Odd', 0);
23720
23721/**
23722 * @ngdoc directive
23723 * @name ngClassEven
23724 * @restrict AC
23725 *
23726 * @description
23727 * The `ngClassOdd` and `ngClassEven` directives work exactly as
23728 * {@link ng.directive:ngClass ngClass}, except they work in
23729 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23730 *
23731 * This directive can be applied only within the scope of an
23732 * {@link ng.directive:ngRepeat ngRepeat}.
23733 *
23734 * @element ANY
23735 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
23736 *   result of the evaluation can be a string representing space delimited class names or an array.
23737 *
23738 * @example
23739   <example>
23740     <file name="index.html">
23741        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23742          <li ng-repeat="name in names">
23743           <span ng-class-odd="'odd'" ng-class-even="'even'">
23744             {{name}} &nbsp; &nbsp; &nbsp;
23745           </span>
23746          </li>
23747        </ol>
23748     </file>
23749     <file name="style.css">
23750       .odd {
23751         color: red;
23752       }
23753       .even {
23754         color: blue;
23755       }
23756     </file>
23757     <file name="protractor.js" type="protractor">
23758       it('should check ng-class-odd and ng-class-even', function() {
23759         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23760           toMatch(/odd/);
23761         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23762           toMatch(/even/);
23763       });
23764     </file>
23765   </example>
23766 */
23767var ngClassEvenDirective = classDirective('Even', 1);
23768
23769/**
23770 * @ngdoc directive
23771 * @name ngCloak
23772 * @restrict AC
23773 *
23774 * @description
23775 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
23776 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
23777 * directive to avoid the undesirable flicker effect caused by the html template display.
23778 *
23779 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
23780 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
23781 * of the browser view.
23782 *
23783 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
23784 * `angular.min.js`.
23785 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
23786 *
23787 * ```css
23788 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
23789 *   display: none !important;
23790 * }
23791 * ```
23792 *
23793 * When this css rule is loaded by the browser, all html elements (including their children) that
23794 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
23795 * during the compilation of the template it deletes the `ngCloak` element attribute, making
23796 * the compiled element visible.
23797 *
23798 * For the best result, the `angular.js` script must be loaded in the head section of the html
23799 * document; alternatively, the css rule above must be included in the external stylesheet of the
23800 * application.
23801 *
23802 * Legacy browsers, like IE7, do not provide attribute selector support (a
23802dded in CSS 2.1) so they
23803 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
23804 * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
23805 *
23806 * @element ANY
23807 *
23808 * @example
23809   <example>
23810     <file name="index.html">
23811        <div id="template1" ng-cloak>{{ 'hello' }}</div>
23812        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
23813     </file>
23814     <file name="protractor.js" type="protractor">
23815       it('should remove the template directive and css class', function() {
23816         expect($('#template1').getAttribute('ng-cloak')).
23817           toBeNull();
23818         expect($('#template2').getAttribute('ng-cloak')).
23819           toBeNull();
23820       });
23821     </file>
23822   </example>
23823 *
23824 */
23825var ngCloakDirective = ngDirective({
23826  compile: function(element, attr) {
23827    attr.$set('ngCloak', undefined);
23828    element.removeClass('ng-cloak');
23829  }
23830});
23831
23832/**
23833 * @ngdoc directive
23834 * @name ngController
23835 *
23836 * @description
23837 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
23838 * supports the principles behind the Model-View-Controller design pattern.
23839 *
23840 * MVC components in angular:
23841 *
23842 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
23843 *   are accessed through bindings.
23844 * * View — The template (HTML with data bindings) that is rendered into the View.
23845 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
23846 *   logic behind the application to decorate the scope with functions and values
23847 *
23848 * Note that you can also attach controllers to the DOM by declaring it in a route definition
23849 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
23850 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
23851 * and executed twice.
23852 *
23853 * @element ANY
23854 * @scope
23855 * @param {expression} ngController Name of a globally accessible constructor function or an
23856 *     {@link guide/expression expression} that on the current scope evaluates to a
23857 *     constructor function. The controller instance can be published into a scope property
23858 *     by specifying `as propertyName`.
23859 *
23860 * @example
23861 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
23862 * greeting are methods declared on the controller (see source tab). These methods can
23863 * easily be called from the angular markup. Any changes to the data are automatically reflected
23864 * in the View without the need for a manual update.
23865 *
23866 * Two different declaration styles are included below:
23867 *
23868 * * one binds methods and properties directly onto the controller using `this`:
23869 * `ng-controller="SettingsController1 as settings"`
23870 * * one injects `$scope` into the controller:
23871 * `ng-controller="SettingsController2"`
23872 *
23873 * The second option is more common in the Angular community, and is generally used in boilerplates
23874 * and in this guide. However, there are advantages to binding properties directly to the controller
23875 * and avoiding scope.
23876 *
23877 * * Using `controller as` makes it obvious which controller you are accessing in the template when
23878 * multiple controllers apply to an element.
23879 * * If you are writing your controllers as classes you have easier access to the properties and
23880 * methods, which will appear on the scope, from inside the controller code.
23881 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
23882 * inheritance masking primitives.
23883 *
23884 * This example demonstrates the `controller as` syntax.
23885 *
23886 * <example name="ngControllerAs" module="controllerAsExample">
23887 *   <file name="index.html">
23888 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
23889 *      Name: <input type="text" ng-model="settings.name"/>
23890 *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
23891 *      Contact:
23892 *      <ul>
23893 *        <li ng-repeat="contact in settings.contacts">
23894 *          <select ng-model="contact.type">
23895 *             <option>phone</option>
23896 *             <option>email</option>
23897 *          </select>
23898 *          <input type="text" ng-model="contact.value"/>
23899 *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
23900 *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
23901 *        </li>
23902 *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
23903 *     </ul>
23904 *    </div>
23905 *   </file>
23906 *   <file name="app.js">
23907 *    angular.module('controllerAsExample', [])
23908 *      .controller('SettingsController1', SettingsController1);
23909 *
23910 *    function SettingsController1() {
23911 *      this.name = "John Smith";
23912 *      this.contacts = [
23913 *        {type: 'phone', value: '408 555 1212'},
23914 *        {type: 'email', value: '[email protected]'} ];
23915 *    }
23916 *
23917 *    SettingsController1.prototype.greet = function() {
23918 *      alert(this.name);
23919 *    };
23920 *
23921 *    SettingsController1.prototype.addContact = function() {
23922 *      this.contacts.push({type: 'email', value: '[email protected]'});
23923 *    };
23924 *
23925 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
23926 *     var index = this.contacts.indexOf(contactToRemove);
23927 *      this.contacts.splice(index, 1);
23928 *    };
23929 *
23930 *    SettingsController1.prototype.clearContact = function(contact) {
23931 *      contact.type = 'phone';
23932 *      contact.value = '';
23933 *    };
23934 *   </file>
23935 *   <file name="protractor.js" type="protractor">
23936 *     it('should check controller as', function() {
23937 *       var container = element(by.id('ctrl-as-exmpl'));
23938 *         expect(container.element(by.model('settings.name'))
23939 *           .getAttribute('value')).toBe('John Smith');
23940 *
23941 *       var firstRepeat =
23942 *           container.element(by.repeater('contact in settings.contacts').row(0));
23943 *       var secondRepeat =
23944 *           container.element(by.repeater('contact in settings.contacts').row(1));
23945 *
23946 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23947 *           .toBe('408 555 1212');
23948 *
23949 *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23950 *           .toBe('[email protected]');
23951 *
23952 *       firstRepeat.element(by.linkText('clear')).click();
23953 *
23954 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23955 *           .toBe('');
23956 *
23957 *       container.element(by.linkText('add')).click();
23958 *
23959 *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
23960 *           .element(by.model('contact.value'))
23961 *           .getAttribute('value'))
23962 *           .toBe('[email protected]');
23963 *     });
23964 *   </file>
23965 * </example>
23966 *
23967 * This example demonstrates the "attach to `$scope`" style of controller.
23968 *
23969 * <example name="ngController" module="controllerExample">
23970 *  <file name="index.html">
23971 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
23972 *     Name: <input type="text" ng-model="name"/>
23973 *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
23974 *     Contact:
23975 *     <ul>
23976 *       <li ng-repeat="contact in contacts">
23977 *         <select ng-model="contact.type">
23978 *            <option>phone</option>
23979 *            <option>email</option>
23980 *         </select>
23981 *         <input type="text" ng-model="contact.value"/>
23982 *         [ <a href="" ng-click="clearContact(contact)">clear</a>
23983 *         | <a href="" ng-click="removeContact(contact)">X</a> ]
23984 *       </li>
23985 *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
23986 *    </ul>
23987 *   </div>
23988 *  </file>
23989 *  <file name="app.js">
23990 *   angular.module('controllerExample', [])
23991 *     .controller('SettingsController2', ['$scope', SettingsController2]);
23992 *
23993 *   function SettingsController2($scope) {
23994 *     $scope.name = "John Smith";
23995 *     $scope.contacts = [
23996 *       {type:'phone', value:'408 555 1212'},
23997 *       {type:'email', value:'[email protected]'} ];
23998 *
23999 *     $scope.greet = function() {
24000 *       alert($scope.name);
24001 *     };
24002 *
24003 *     $scope.addContact = function() {
24004 *       $scope.contacts.push({type:'email', value:'[email protected]'});
24005 *     };
24006 *
24007 *     $scope.removeContact = function(contactToRemove) {
24008 *       var index = $scope.contacts.indexOf(contactToRemove);
24009 *       $scope.contacts.splice(index, 1);
24010 *     };
24011 *
24012 *     $scope.clearContact = function(contact) {
24013 *       contact.type = 'phone';
24014 *       contact.value = '';
24015 *     };
24016 *   }
24017 *  </file>
24018 *  <file name="protractor.js" type="protractor">
24019 *    it('should check controller', function() {
24020 *      var container = element(by.id('ctrl-exmpl'));
24021 *
24022 *      expect(container.element(by.model('name'))
24023 *          .getAttribute('value')).toBe('John Smith');
24024 *
24025 *      var firstRepeat =
24026 *          container.element(by.repeater('contact in contacts').row(0));
24027 *      var secondRepeat =
24028 *          container.element(by.repeater('contact in contacts').row(1));
24029 *
24030 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
24031 *          .toBe('408 555 1212');
24032 *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
24033 *          .toBe('[email protected]');
24034 *
24035 *      firstRepeat.element(by.linkText('clear')).click();
24036 *
24037 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
24038 *          .toBe('');
24039 *
24040 *      container.element(by.linkText('add')).click();
24041 *
24042 *      expect(container.element(by.repeater('contact in contacts').row(2))
24043 *          .element(by.model('contact.value'))
24044 *          .getAttribute('value'))
24045 *          .toBe('[email protected]');
24046 *    });
24047 *  </file>
24048 *</example>
24049
24050 */
24051var ngControllerDirective = [function() {
24052  return {
24053    scope: true,
24054    controller: '@',
24055    priority: 500
24056  };
24057}];
24058
24059/**
24060 * @ngdoc directive
24061 * @name ngCsp
24062 *
24063 * @element html
24064 * @description
24065 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
24066 *
24067 * This is necessary when developing things like Google Chrome Extensions.
24068 *
24069 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
24070 * For Angular to be CSP compatible there are only two things that we need to do differently:
24071 *
24072 * - don't use `Function` constructor to generate optimized value getters
24073 * - don't inject custom stylesheet into the document
24074 *
24075 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
24076 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
24077 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
24078 * be raised.
24079 *
24080 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
24081 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
24082 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
24083 *
24084 * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
24085 * autodetection however triggers a CSP error to be logged in the console:
24086 *
24087 * ```
24088 * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
24089 * script in the following Content Security Policy directive: "default-src 'self'". Note that
24090 * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
24091 * ```
24092 *
24093 * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
24094 * directive on the root element of the application or on the `angular.js` script tag, whichever
24095 * appears first in the html document.
24096 *
24097 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
24098 *
24099 * @example
24100 * This example shows how to apply the `ngCsp` directive to the `html` tag.
24101   ```html
24102     <!doctype html>
24103     <html ng-app ng-csp>
24104     ...
24105     ...
24106     </html>
24107   ```
24108 */
24109
24110// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
24111// bootstrap the system (before $parse is instantiated), for this reason we just have
24112// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
24113
24114/**
24115 * @ngdoc directive
24116 * @name ngClick
24117 *
24118 * @description
24119 * The ngClick directive allows you to specify custom behavior when
24120 * an element is clicked.
24121 *
24122 * @element ANY
24123 * @priority 0
24124 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
24125 * click. ({@link guide/expression#-event- Event object is available as `$event`})
24126 *
24127 * @example
24128   <example>
24129     <file name="index.html">
24130      <button ng-click="count = count + 1" ng-init="count=0">
24131        Increment
24132      </button>
24133      <span>
24134        count: {{count}}
24135      <span>
24136     </file>
24137     <file name="protractor.js" type="protractor">
24138       it('should check ng-click', function() {
24139         expect(element(by.binding('count')).getText()).toMatch('0');
24140         element(by.css('button')).click();
24141         expect(element(by.binding('count')).getText()).toMatch('1');
24142       });
24143     </file>
24144   </example>
24145 */
24146/*
24147 * A directive that allows creation of custom onclick handlers that are defined as angular
24148 * expressions and are compiled and executed within the current scope.
24149 *
24150 * Events that are handled via these handler are always configured not to propagate further.
24151 */
24152var ngEventDirectives = {};
24153
24154// For events that might fire synchronously during DOM manipulation
24155// we need to execute their event handlers asynchronously using $evalAsync,
24156// so that they are not executed in an inconsistent state.
24157var forceAsyncEvents = {
24158  'blur': true,
24159  'focus': true
24160};
24161forEach(
24162  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
24163  function(eventName) {
24164    var directiveName = directiveNormalize('ng-' + eventName);
24165    ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
24166      return {
24167        compile: function($element, attr) {
24168          var fn = $parse(attr[directiveName]);
24169          return function ngEventHandler(scope, element) {
24170            element.on(eventName, function(event) {
24171              var callback = function() {
24172                fn(scope, {$event:event});
24173              };
24174              if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
24175                scope.$evalAsync(callback);
24176              } else {
24177                scope.$apply(callback);
24178              }
24179            });
24180          };
24181        }
24182      };
24183    }];
24184  }
24185);
24186
24187/**
24188 * @ngdoc directive
24189 * @name ngDblclick
24190 *
24191 * @description
24192 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
24193 *
24194 * @element ANY
24195 * @priority 0
24196 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
24197 * a dblclick. (The Event object is available as `$event`)
24198 *
24199 * @example
24200   <example>
24201     <file name="index.html">
24202      <button ng-dblclick="count = count + 1" ng-init="count=0">
24203        Increment (on double click)
24204      </button>
24205      count: {{count}}
24206     </file>
24207   </example>
24208 */
24209
24210
24211/**
24212 * @ngdoc directive
24213 * @name ngMousedown
24214 *
24215 * @description
24216 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
24217 *
24218 * @element ANY
24219 * @priority 0
24220 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
24221 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
24222 *
24223 * @example
24224   <example>
24225     <file name="index.html">
24226      <button ng-mousedown="count = count + 1" ng-init="count=0">
24227        Increment (on mouse down)
24228      </button>
24229      count: {{count}}
24230     </file>
24231   </example>
24232 */
24233
24234
24235/**
24236 * @ngdoc directive
24237 * @name ngMouseup
24238 *
24239 * @description
24240 * Specify custom behavior on mouseup event.
24241 *
24242 * @element ANY
24243 * @priority 0
24244 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
24245 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
24246 *
24247 * @example
24248   <example>
24249     <file name="index.html">
24250      <button ng-mouseup="count = count + 1" ng-init="count=0">
24251        Increment (on mouse up)
24252      </button>
24253      count: {{count}}
24254     </file>
24255   </example>
24256 */
24257
24258/**
24259 * @ngdoc directive
24260 * @name ngMouseover
24261 *
24262 * @description
24263 * Specify custom behavior on mouseover event.
24264 *
24265 * @element ANY
24266 * @priority 0
24267 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
24268 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
24269 *
24270 * @example
24271   <example>
24272     <file name="index.html">
24273      <button ng-mouseover="count = count + 1" ng-init="count=0">
24274        Increment (when mouse is over)
24275      </button>
24276      count: {{count}}
24277     </file>
24278   </example>
24279 */
24280
24281
24282/**
24283 * @ngdoc directive
24284 * @name ngMouseenter
24285 *
24286 * @description
24287 * Specify custom behavior on mouseenter event.
24288 *
24289 * @element ANY
24290 * @priority 0
24291 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
24292 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
24293 *
24294 * @example
24295   <example>
24296     <file name="index.html">
24297      <button ng-mouseenter="count = count + 1" ng-init="count=0">
24298        Increment (when mouse enters)
24299      </button>
24300      count: {{count}}
24301     </file>
24302   </example>
24303 */
24304
24305
24306/**
24307 * @ngdoc directive
24308 * @name ngMouseleave
24309 *
24310 * @description
24311 * Specify custom behavior on mouseleave event.
24312 *
24313 * @element ANY
24314 * @priority 0
24315 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
24316 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
24317 *
24318 * @example
24319   <example>
24320     <file name="index.html">
24321      <button ng-mouseleave="count = count + 1" ng-init="count=0">
24322        Increment (when mouse leaves)
24323      </button>
24324      count: {{count}}
24325     </file>
24326   </example>
24327 */
24328
24329
24330/**
24331 * @ngdoc directive
24332 * @name ngMousemove
24333 *
24334 * @description
24335 * Specify custom behavior on mousemove event.
24336 *
24337 * @element ANY
24338 * @priority 0
24339 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
24340 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
24341 *
24342 * @example
24343   <example>
24344     <file name="index.html">
24345      <button ng-mousemove="count = count + 1" ng-init="count=0">
24346        Increment (when mouse moves)
24347      </button>
24348      count: {{count}}
24349     </file>
24350   </example>
24351 */
24352
24353
24354/**
24355 * @ngdoc directive
24356 * @name ngKeydown
24357 *
24358 * @description
24359 * Specify custom behavior on keydown event.
24360 *
24361 * @element ANY
24362 * @priority 0
24363 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
24364 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
24365 *
24366 * @example
24367   <example>
24368     <file name="index.html">
24369      <input ng-keydown="count = count + 1" ng-init="count=0">
24370      key down count: {{count}}
24371     </file>
24372   </example>
24373 */
24374
24375
24376/**
24377 * @ngdoc directive
24378 * @name ngKeyup
24379 *
24380 * @description
24381 * Specify custom behavior on keyup event.
24382 *
24383 * @element ANY
24384 * @priority 0
24385 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
24386 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
24387 *
24388 * @example
24389   <example>
24390     <file name="index.html">
24391       <p>Typing in the input box below updates the key count</p>
24392       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
24393
24394       <p>Typing in the input box below updates the keycode</p>
24395       <input ng-keyup="event=$event">
24396       <p>event keyCode: {{ event.keyCode }}</p>
24397       <p>event altKey: {{ event.altKey }}</p>
24398     </file>
24399   </example>
24400 */
24401
24402
24403/**
24404 * @ngdoc directive
24405 * @name ngKeypress
24406 *
24407 * @description
24408 * Specify custom behavior on keypress event.
24409 *
24410 * @element ANY
24411 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
24412 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
24413 * and can be interrogated for keyCode, altKey, etc.)
24414 *
24415 * @example
24416   <example>
24417     <file name="index.html">
24418      <input ng-keypress="count = count + 1" ng-init="count=0">
24419      key press count: {{count}}
24420     </file>
24421   </example>
24422 */
24423
24424
24425/**
24426 * @ngdoc directive
24427 * @name ngSubmit
24428 *
24429 * @description
24430 * Enables binding angular expressions to onsubmit events.
24431 *
24432 * Additionally it prevents the default action (which for form means 
24432sending the request to the
24433 * server and reloading the current page), but only if the form does not contain `action`,
24434 * `data-action`, or `x-action` attributes.
24435 *
24436 * <div class="alert alert-warning">
24437 * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
24438 * `ngSubmit` handlers together. See the
24439 * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
24440 * for a detailed discussion of when `ngSubmit` may be triggered.
24441 * </div>
24442 *
24443 * @element form
24444 * @priority 0
24445 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
24446 * ({@link guide/expression#-event- Event object is available as `$event`})
24447 *
24448 * @example
24449   <example module="submitExample">
24450     <file name="index.html">
24451      <script>
24452        angular.module('submitExample', [])
24453          .controller('ExampleController', ['$scope', function($scope) {
24454            $scope.list = [];
24455            $scope.text = 'hello';
24456            $scope.submit = function() {
24457              if ($scope.text) {
24458                $scope.list.push(this.text);
24459                $scope.text = '';
24460              }
24461            };
24462          }]);
24463      </script>
24464      <form ng-submit="submit()" ng-controller="ExampleController">
24465        Enter text and hit enter:
24466        <input type="text" ng-model="text" name="text" />
24467        <input type="submit" id="submit" value="Submit" />
24468        <pre>list={{list}}</pre>
24469      </form>
24470     </file>
24471     <file name="protractor.js" type="protractor">
24472       it('should check ng-submit', function() {
24473         expect(element(by.binding('list')).getText()).toBe('list=[]');
24474         element(by.css('#submit')).click();
24475         expect(element(by.binding('list')).getText()).toContain('hello');
24476         expect(element(by.model('text')).getAttribute('value')).toBe('');
24477       });
24478       it('should ignore empty strings', function() {
24479         expect(element(by.binding('list')).getText()).toBe('list=[]');
24480         element(by.css('#submit')).click();
24481         element(by.css('#submit')).click();
24482         expect(element(by.binding('list')).getText()).toContain('hello');
24483        });
24484     </file>
24485   </example>
24486 */
24487
24488/**
24489 * @ngdoc directive
24490 * @name ngFocus
24491 *
24492 * @description
24493 * Specify custom behavior on focus event.
24494 *
24495 * Note: As the `focus` event is executed synchronously when calling `input.focus()`
24496 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
24497 * during an `$apply` to ensure a consistent state.
24498 *
24499 * @element window, input, select, textarea, a
24500 * @priority 0
24501 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
24502 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
24503 *
24504 * @example
24505 * See {@link ng.directive:ngClick ngClick}
24506 */
24507
24508/**
24509 * @ngdoc directive
24510 * @name ngBlur
24511 *
24512 * @description
24513 * Specify custom behavior on blur event.
24514 *
24515 * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
24516 * an element has lost focus.
24517 *
24518 * Note: As the `blur` event is executed synchronously also during DOM manipulations
24519 * (e.g. removing a focussed input),
24520 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
24521 * during an `$apply` to ensure a consistent state.
24522 *
24523 * @element window, input, select, textarea, a
24524 * @priority 0
24525 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
24526 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
24527 *
24528 * @example
24529 * See {@link ng.directive:ngClick ngClick}
24530 */
24531
24532/**
24533 * @ngdoc directive
24534 * @name ngCopy
24535 *
24536 * @description
24537 * Specify custom behavior on copy event.
24538 *
24539 * @element window, input, select, textarea, a
24540 * @priority 0
24541 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
24542 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
24543 *
24544 * @example
24545   <example>
24546     <file name="index.html">
24547      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
24548      copied: {{copied}}
24549     </file>
24550   </example>
24551 */
24552
24553/**
24554 * @ngdoc directive
24555 * @name ngCut
24556 *
24557 * @description
24558 * Specify custom behavior on cut event.
24559 *
24560 * @element window, input, select, textarea, a
24561 * @priority 0
24562 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
24563 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
24564 *
24565 * @example
24566   <example>
24567     <file name="index.html">
24568      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
24569      cut: {{cut}}
24570     </file>
24571   </example>
24572 */
24573
24574/**
24575 * @ngdoc directive
24576 * @name ngPaste
24577 *
24578 * @description
24579 * Specify custom behavior on paste event.
24580 *
24581 * @element window, input, select, textarea, a
24582 * @priority 0
24583 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
24584 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
24585 *
24586 * @example
24587   <example>
24588     <file name="index.html">
24589      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
24590      pasted: {{paste}}
24591     </file>
24592   </example>
24593 */
24594
24595/**
24596 * @ngdoc directive
24597 * @name ngIf
24598 * @restrict A
24599 *
24600 * @description
24601 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
24602 * {expression}. If the expression assigned to `ngIf` evaluates to a false
24603 * value then the element is removed from the DOM, otherwise a clone of the
24604 * element is reinserted into the DOM.
24605 *
24606 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
24607 * element in the DOM rather than changing its visibility via the `display` css property.  A common
24608 * case when this difference is significant is when using css selectors that rely on an element's
24609 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
24609s.
24610 *
24611 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
24612 * is created when the element is restored.  The scope created within `ngIf` inherits from
24613 * its parent scope using
24614 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance).
24615 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
24616 * a javascript primitive defined in the parent scope. In this case any modifications made to the
24617 * variable within the child scope will override (hide) the value in the parent scope.
24618 *
24619 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
24620 * is if an element's class attribute is directly modified after it's compiled, using something like
24621 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
24622 * the added class will be lost because the original compiled state is used to regenerate the element.
24623 *
24624 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
24625 * and `leave` effects.
24626 *
24627 * @animations
24628 * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
24629 * leave - happens just before the ngIf contents are removed from the DOM
24630 *
24631 * @element ANY
24632 * @scope
24633 * @priority 600
24634 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
24635 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
24636 *     element is added to the DOM tree.
24637 *
24638 * @example
24639  <example module="ngAnimate" deps="angular-animate.js" animations="true">
24640    <file name="index.html">
24641      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
24642      Show when checked:
24643      <span ng-if="checked" class="animate-if">
24644        I'm removed when the checkbox is unchecked.
24645      </span>
24646    </file>
24647    <file name="animations.css">
24648      .animate-if {
24649        background:white;
24650        border:1px solid black;
24651        padding:10px;
24652      }
24653
24654      .animate-if.ng-enter, .animate-if.ng-leave {
24655        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24656        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24657      }
24658
24659      .animate-if.ng-enter,
24660      .animate-if.ng-leave.ng-leave-active {
24661        opacity:0;
24662      }
24663
24664      .animate-if.ng-leave,
24665      .animate-if.ng-enter.ng-enter-active {
24666        opacity:1;
24667      }
24668    </file>
24669  </example>
24670 */
24671var ngIfDirective = ['$animate', function($animate) {
24672  return {
24673    transclude: 'element',
24674    priority: 600,
24675    terminal: true,
24676    restrict: 'A',
24677    $$tlb: true,
24678    link: function ($scope, $element, $attr, ctrl, $transclude) {
24679        var block, childScope, previousElements;
24680        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
24681
24682          if (toBoolean(value)) {
24683            if (!childScope) {
24684              childScope = $scope.$new();
24685              $transclude(childScope, function (clone) {
24686                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
24687                // Note: We only need the first/last node of the cloned nodes.
24688                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
24689                // by a directive with templateUrl when its template arrives.
24690                block = {
24691                  clone: clone
24692                };
24693                $animate.enter(clone, $element.parent(), $element);
24694              });
24695            }
24696          } else {
24697            if(previousElements) {
24698              previousElements.remove();
24699              previousElements = null;
24700            }
24701            if(childScope) {
24702              childScope.$destroy();
24703              childScope = null;
24704            }
24705            if(block) {
24706              previousElements = getBlockElements(block.clone);
24707              $animate.leave(previousElements, function() {
24708                previousElements = null;
24709              });
24710              block = null;
24711            }
24712          }
24713        });
24714    }
24715  };
24716}];
24717
24718/**
24719 * @ngdoc directive
24720 * @name ngInclude
24721 * @restrict ECA
24722 *
24723 * @description
24724 * Fetches, compiles and includes an external HTML fragment.
24725 *
24726 * By default, the template URL is restricted to the same domain and protocol as the
24727 * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
24728 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
24729 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
24730 * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
24731 * ng.$sce Strict Contextual Escaping}.
24732 *
24733 * In addition, the browser's
24734 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
24735 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
24736 * policy may further restrict whether the template is successfully loaded.
24737 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
24738 * access on some browsers.
24739 *
24740 * @animations
24741 * enter - animation is used to bring new content into the browser.
24742 * leave - animation is used to animate existing content away.
24743 *
24744 * The enter and leave animation occur concurrently.
24745 *
24746 * @scope
24747 * @priority 400
24748 *
24749 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
24750 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
24751 * @param {string=} onload Expression to evaluate when a new partial is loaded.
24752 *
24753 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
24754 *                  $anchorScroll} to scroll the viewport after the content is loaded.
24755 *
24756 *                  - If the attribute is not set, disable scrolling.
24757 *                  - If the attribute is set without value, enable scrolling.
24758 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
24759 *
24760 * @example
24761  <example module="includeExample" deps="angular-animate.js" animations="true">
24762    <file name="index.html">
24763     <div ng-controller="ExampleController">
24764       <select ng-model="template" ng-options="t.name for t in templates">
24765        <option value="">(blank)</option>
24766       </select>
24767       url of the template: <tt>{{template.url}}</tt>
24768       <hr/>
24769       <div class="slide-animate-container">
24770         <div class="slide-animate" ng-include="template.url"></div>
24771       </div>
24772     </div>
24773    </file>
24774    <file name="script.js">
24775      angular.module('includeExample', ['ngAnimate'])
24776        .controller('ExampleController', ['$scope', function($scope) {
24777          $scope.templates =
24778            [ { name: 'template1.html', url: 'template1.html'},
24779              { name: 'template2.html', url: 'template2.html'} ];
24780          $scope.template = $scope.templates[0];
24781        }]);
24782     </file>
24783    <file name="template1.html">
24784      Content of template1.html
24785    </file>
24786    <file name="template2.html">
24787      Content of template2.html
24788    </file>
24789    <file name="animations.css">
24790      .slide-animate-container {
24791        position:relative;
24792        background:white;
24793        border:1px solid black;
24794        height:40px;
24795        overflow:hidden;
24796      }
24797
24798      .slide-animate {
24799        padding:10px;
24800      }
24801
24802      .slide-animate.ng-enter, .slide-animate.ng-leave {
24803        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24804        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24805
24806        position:absolute;
24807        top:0;
24808        left:0;
24809        right:0;
24810        bottom:0;
24811        display:block;
24812        padding:10px;
24813      }
24814
24815      .slide-animate.ng-enter {
24816        top:-50px;
24817      }
24818      .slide-animate.ng-enter.ng-enter-active {
24819        top:0;
24820      }
24821
24822      .slide-animate.ng-leave {
24823        top:0;
24824      }
24825      .slide-animate.ng-leave.ng-leave-active {
24826        top:50px;
24827      }
24828    </file>
24829    <file name="protractor.js" type="protractor">
24830      var templateSelect = element(by.model('template'));
24831      var includeElem = element(by.css('[ng-include]'));
24832
24833      it('should load template1.html', function() {
24834        expect(includeElem.getText()).toMatch(/Content of template1.html/);
24835      });
24836
24837      it('should load template2.html', function() {
24838        if (browser.params.browser == 'firefox') {
24839          // Firefox can't handle using selects
24840          // See https://github.com/angular/protractor/issues/480
24841          return;
24842        }
24843        templateSelect.click();
24844        templateSelect.all(by.css('option')).get(2).click();
24845        expect(includeElem.getText()).toMatch(/Content of template2.html/);
24846      });
24847
24848      it('should change to blank', function() {
24849        if (browser.params.browser == 'firefox') {
24850          // Firefox can't handle using selects
24851          return;
24852        }
24853        templateSelect.click();
24854        templateSelect.all(by.css('option')).get(0).click();
24855        expect(includeElem.isPresent()).toBe(false);
24856      });
24857    </file>
24858  </example>
24859 */
24860
24861
24862/**
24863 * @ngdoc event
24864 * @name ngInclude#$includeContentRequested
24865 * @eventType emit on the scope ngInclude was declared in
24866 * @description
24867 * Emitted every time the ngInclude content is requested.
24868 */
24869
24870
24871/**
24872 * @ngdoc event
24873 * @name ngInclude#$includeContentLoaded
24874 * @eventType emit on the current ngInclude scope
24875 * @description
24876 * Emitted every time the ngInclude content is reloaded.
24877 */
24878var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
24879                  function($http,   $templateCache,   $anchorScroll,   $animate,   $sce) {
24880  return {
24881    restrict: 'ECA',
24882    priority: 400,
24883    terminal: true,
24884    transclude: 'element',
24885    controller: angular.noop,
24886    compile: function(element, attr) {
24887      var srcExp = attr.ngInclude || attr.src,
24888          onloadExp = attr.onload || '',
24889          autoScrollExp = attr.autoscroll;
24890
24891      return function(scope, $element, $attr, ctrl, $transclude) {
24892        var changeCounter = 0,
24893            currentScope,
24894            previousElement,
24895            currentElement;
24896
24897        var cleanupLastIncludeContent = function() {
24898          if(previousElement) {
24899            previousElement.remove();
24900            previousElement = null;
24901          }
24902          if(currentScope) {
24903            currentScope.$destroy();
24904            currentScope = null;
24905          }
24906          if(currentElement) {
24907            $animate.leave(currentElement, function() {
24908              previousElement = null;
24909            });
24910            previousElement = currentElement;
24911            currentElement = null;
24912          }
24913        };
24914
24915        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
24916          var afterAnimation = function() {
24917            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
24918              $anchorScroll();
24919            }
24920          };
24921          var thisChangeId = ++changeCounter;
24922
24923          if (src) {
24924            $http.get(src, {cache: $templateCache}).success(function(response) {
24925              if (thisChangeId !== changeCounter) return;
24926              var newScope = scope.$new();
24927              ctrl.template = response;
24928
24929              // Note: This will also link all children of ng-include that were contained in the original
24930              // html. If that content contains controllers, ... they could pollute/change the scope.
24931              // However, using ng-include on an element with additional content does not make sense...
24932              // Note: We can't remove them in the cloneAttchFn of $transclude as that
24933              // function is called before linking the content, which would apply child
24934              // directives to non existing elements.
24935              var clone = $transclude(newScope, function(clone) {
24936                cleanupLastIncludeContent();
24937                $animate.enter(clone, null, $element, afterAnimation);
24938              });
24939
24940              currentScope = newScope;
24941              currentElement = clone;
24942
24943              currentScope.$emit('$includeContentLoaded');
24944              scope.$eval(onloadExp);
24945            }).error(function() {
24946              if (thisChangeId === changeCounter) cleanupLastIncludeContent();
24947            });
24948            scope.$emit('$includeContentRequested');
24949          } else {
24950            cleanupLastIncludeContent();
24951            ctrl.template = null;
24952          }
24953        });
24954      };
24955    }
24956  };
24957}];
24958
24959// This directive is called during the $transclude call of the first `ngInclude` directive.
24960// It will replace and compile the content of the element with the loaded template.
24961// We need this directive so that the element content is already filled when
24962// the link function of another directive on the same element as ngInclude
24963// is called.
24964var ngIncludeFillContentDirective = ['$compile',
24965  function($compile) {
24966    return {
24967      restrict: 'ECA',
24968      priority: -400,
24969      require: 'ngInclude',
24970      link: function(scope, $element, $attr, ctrl) {
24971        $element.html(ctrl.template);
24972        $compile($element.contents())(scope);
24973      }
24974    };
24975  }];
24976
24977/**
24978 * @ngdoc directive
24979 * @name ngInit
24980 * @restrict AC
24981 *
24982 * @description
24983 * The `ngInit` directive allows you to evaluate an expression in the
24984 * current scope.
24985 *
24986 * <div class="alert alert-error">
24987 * The only appropriate use of `ngInit` is for aliasing special properties of
24988 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
24989 * should use {@link guide/controller controllers} rather than `ngInit`
24990 * to initialize values on a scope.
24991 * </div>
24992 * <div class="alert alert-warning">
24993 * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
24994 * sure you have parenthesis for correct precedence:
24995 * <pre class="prettyprint">
24996 *   <div ng-init="test1 = (data | orderBy:'name')"></div>
24997 * </pre>
24998 * </div>
24999 *
25000 * @priority 450
25001 *
25002 * @element ANY
25003 * @param {expression} ngInit {@link guide/expression Expression} to eval.
25004 *
25005 * @example
25006   <example module="initExample">
25007     <file name="index.html">
25008   <script>
25009     angular.module('initExample', [])
25010       .controller('ExampleController', ['$scope', function($scope) {
25011         $scope.list = [['a', 'b'], ['c', 'd']];
25012       }]);
25013   </script>
25014   <div ng-controller="ExampleController">
25015     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
25016       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
25017          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
25018       </div>
25019     </div>
25020   </div>
25021     </file>
25022     <file name="protractor.js" type="protractor">
25023       it('should alias index positions', function() {
25024         var elements = element.all(by.css('.example-init'));
25025         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
25026         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
25027         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
25028         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
25029       });
25030     </file>
25031   </example>
25032 */
25033var ngInitDirective = ngDirective({
25034  priority: 450,
25035  compile: function() {
25036    return {
25037      pre: function(scope, element, attrs) {
25038        scope.$eval(attrs.ngInit);
25039      }
25040    };
25041  }
25042});
25043
25044/**
25045 * @ngdoc directive
25046 * @name ngNonBindable
25047 * @restrict AC
25048 * @priority 1000
25049 *
25050 * @description
25051 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
25052 * DOM element. This is useful if the element contains what appears to be Angular directives and
25053 * bindings but which should be ignored by Angular. This could be the case if you have a site that
25054 * displays snippets of code, for instance.
25055 *
25056 * @element ANY
25057 *
25058 * @example
25059 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
25060 * but the one wrapped in `ngNonBindable` is left alone.
25061 *
25062 * @example
25063    <example>
25064      <file name="index.html">
25065        <div>Normal: {{1 + 2}}</div>
25066        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
25067      </file>
25068      <file name="protractor.js" type="protractor">
25069       it('should check ng-non-bindable', function() {
25070         expect(element(by.binding('1 + 2')).getText()).toContain('3');
25071         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
25072       });
25073      </file>
25074    </example>
25075 */
25076var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
25077
25078/**
25079 * @ngdoc directive
25080 * @name ngPluralize
25081 * @restrict EA
25082 *
25083 * @description
25084 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
25085 * These rules are bundled with angular.js, but can be overridden
25086 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
25087 * by specifying the mappings between
25088 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
25089 * and the strings to be displayed.
25090 *
25091 * # Plural categories and explicit number rules
25092 * There are two
25093 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
25094 * in Angular's default en-US locale: "one" and "other".
25095 *
25096 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
25097 * any number that is not 1), an explicit number rule can only match one number. For example, the
25098 * explicit number rule for "3" matches the number 3. There are examples of plural categories
25099 * and explicit number rules throughout the rest of this documentation.
25100 *
25101 * # Configuring ngPluralize
25102 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
25103 * You can also provide an optional attribute, `offset`.
25104 *
25105 * The value of the `count` attribute can be either a string or an {@link guide/expression
25106 * Angular expression}; these are evaluated on the current scope for its bound value.
25107 *
25108 * The `when` attribute specifies the mappings between plural categories and the actual
25109 * string to be displayed. The value of the attribute should be a JSON object.
25110 *
25111 * The following example shows how to configure ngPluralize:
25112 *
25113 * ```html
25114 * <ng-pluralize count="personCount"
25115                 when="{'0': 'Nobody is viewing.',
25116 *                      'one': '1 person is viewing.',
25117 *                      'other': '{} people are viewing.'}">
25118 * </ng-pluralize>
25119 *```
25120 *
25121 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
25122 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
25123 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
25124 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
25125 * show "a dozen people are viewing".
25126 *
25127 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
25128 * into pluralized strings. In the previous example, Angular will replace `{}` with
25129 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
25130 * for <span ng-non-bindable>{{numberExpression}}</span>.
25131 *
25132 * # Configuring ngPluralize with offset
25133 * The `offset` attribute allows further customization of pluralized text, which can result in
25134 * a better user experience. For example, instead of the message "4 people are viewing this document",
25135 * you might display "John, Kate and 2 others are viewing this document".
25136 * The offset attribute allows you to offset a number by any desired value.
25137 * Let's take a look at an example:
25138 *
25139 * ```html
25140 * <ng-pluralize count="personCount" offset=2
25141 *               when="{'0': 'Nobody is viewing.',
25142 *                      '1': '{{person1}} is viewing.',
25143 *                      '2': '{{person1}} and {{person2}} are viewing.',
25144 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
25145 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
25146 * </ng-pluralize>
25147 * ```
25148 *
25149 * Notice that we are still using two plural categories(one, other), but we added
25150 * three explicit number rules 0, 1 and 2.
25151 * When one person, perhaps John, views the document, "John is viewing" will be shown.
25152 * When three people view the document, no explicit number rule is found, so
25153 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
25154 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
25155 * is shown.
25156 *
25157 * Note that when you specify offsets, you must provide explicit number rules for
25158 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
25159 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
25160 * plural categories "one" and "other".
25161 *
25162 * @param {string|expression} count The variable to be bound to.
25163 * @param {string} when The mapping between plural category to its corresponding strings.
25164 * @param {number=} offset Offset to deduct from the total number.
25165 *
25166 * @example
25167    <example module="pluralizeExample">
25168      <file name="index.html">
25169        <script>
25170          angular.module('pluralizeExample', [])
25171            .controller('ExampleController', ['$scope', function($scope) {
25172              $scope.person1 = 'Igor';
25173              $scope.person2 = 'Misko';
25174              $scope.personCount = 1;
25175            }]);
25176        </script>
25177        <div ng-controller="ExampleController">
25178          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
25179          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
25180          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
25181
25182          <!--- Example with simple pluralization rules for en locale --->
25183          Without Offset:
25184          <ng-pluralize count="personCount"
25185                        when="{'0': 'Nobody is viewing.',
25186                               'one': '1 person is viewing.',
25187                               'other': '{} people are viewing.'}">
25188          </ng-pluralize><br>
25189
25190          <!--- Example with offset --->
25191          With Offset(2):
25192          <ng-pluralize count="personCount" offset=2
25193                        when="{'0': 'Nobody is viewing.',
25194                               '1': '{{person1}} is viewing.',
25195                               '2': '{{person1}} and {{person2}} are viewing.',
25196                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
25197                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
25198          </ng-pluralize>
25199        </div>
25200      </file>
25201      <file name="protractor.js" type="protractor">
25202        it('should show correct pluralized string', function() {
25203          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
25204          var withOffset = element.all(by.css('ng-pluralize')).get(1);
25205          var countInput = element(by.model('personCount'));
25206
25207          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
25208          expect(withOffset.getText()).toEqual('Igor is viewing.');
25209
25210          countInput.clear();
25211          countInput.sendKeys('0');
25212
25213          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
25214          expect(withOffset.getText()).toEqual('Nobody is viewing.');
25215
25216          countInput.clear();
25217          countInput.sendKeys('2');
25218
25219          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
25220          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
25221
25222          countInput.clear();
25223          countInput.sendKeys('3');
25224
25225          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
25226          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
25227
25228          countInput.clear();
25229          countInput.sendKeys('4');
25230
25231          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
25232          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
25233        });
25234        it('should show data-bound names', function() {
25235          var withOffset = element.all(by.css('ng-pluralize')).get(1);
25236          var personCount = element(by.model('personCount'));
25237          var person1 = element(by.model('person1'));
25238          var person2 = element(by.model('person2'));
25239          personCount.clear();
25240          personCount.sendKeys('4');
25241          person1.clear();
25242          person1.sendKeys('Di');
25243          person2.clear();
25244          person2.sendKeys('Vojta');
25245          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
25246        });
25247      </file>
25248    </example>
25249 */
25250var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
25251  var BRACE = /{}/g;
25252  return {
25253    restrict: 'EA',
25254    link: function(scope, element, attr) {
25255      var numberExp = attr.count,
25256          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
25257          offset = attr.offset || 0,
25258          whens = scope.$eval(whenExp) || {},
25259          whensExpFns = {},
25260          startSymbol = $interpolate.startSymbol(),
25261          endSymbol = $interpolate.endSymbol(),
25262          isWhen = /^when(Minus)?(.+)$/;
25263
25264      forEach(attr, function(expression, attributeName) {
25265        if (isWhen.test(attributeName)) {
25266          whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
25267            element.attr(attr.$attr[attributeName]);
25268        }
25269      });
25270      forEach(whens, function(expression, key) {
25271        whensExpFns[key] =
25272          $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
25273            offset + endSymbol));
25274      });
25275
25276      scope.$watch(function ngPluralizeWatch() {
25277        var value = parseFloat(scope.$eval(numberExp));
25278
25279        if (!isNaN(value)) {
25280          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
25281          //check it against pluralization rules in $locale service
25282          if (!(value in whens)) value = $locale.pluralCat(value - offset);
25283           return whensExpFns[value](scope, element, true);
25284        } else {
25285          return '';
25286        }
25287      }, function ngPluralizeWatchAction(newVal) {
25288        element.text(newVal);
25289      });
25290    }
25291  };
25292}];
25293
25294/**
25295 * @ngdoc directive
25296 * @name ngRepeat
25297 *
25298 * @description
25299 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
25300 * instance gets its own scope, where the given loop variable is set to the current collection item,
25301 * and `$index` is set to the item index or key.
25302 *
25303 * Special properties are exposed on the local scope of each template instance, including:
25304 *
25305 * | Variable  | Type            | Details                                                                     |
25306 * |-----------|-----------------|-----------------------------------------------------------------------------|
25307 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
25308 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
25309 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
25310 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
25311 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
25312 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
25313 *
25314 * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
25315 * This may be useful when, for instance, nesting ngRepeats.
25316 *
25317 * # Special repeat start and end points
25318 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
25319 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
25320 * The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on)
25321 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
25322 *
25323 * The example below makes use of this feature:
25324 * ```html
25325 *   <header ng-repeat-start="item in items">
25326 *     Header {{ item }}
25327 *   </header>
25328 *   <div class="body">
25329 *     Body {{ item }}
25330 *   </div>
25331 *   <footer ng-repeat-end>
25332 *     Footer {{ item }}
25333 *   </footer>
25334 * ```
25335 *
25336 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
25337 * ```html
25338 *   <header>
25339 *     Header A
25340 *   </header>
25341 *   <div class="body">
25342 *     Body A
25343 *   </div>
25344 *   <footer>
25345 *     Footer A
25346 *   </footer>
25347 *   <header>
25348 *     Header B
25349 *   </header>
25350 *   <div class="body">
25351 *     Body B
25352 *   </div>
25353 *   <footer>
25354 *     Footer B
25355 *   </footer>
25356 * ```
25357 *
25358 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
25359 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
25360 *
25361 * @animations
25362 * **.enter** - when a new item is added to the list or when an item is revealed after a filter
25363 *
25364 * **.leave** - when an item is removed from the list or when an item is filtered out
25365 *
25366 * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
25367 *
25368 * @element ANY
25369 * @scope
25370 * @priority 1000
25371 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
25372 *   formats are currently supported:
25373 *
25374 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
25375 *     is a scope expression giving the collection to enumerate.
25376 *
25377 *     For example: `album in artist.albums`.
25378 *
25379 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
25380 *     and `expression` is the scope expression giving the collection to enumerate.
25381 *
25382 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
25383 *
25384 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
25385 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
25386 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
25387 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
25388 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
25389 *     before specifying a tracking expression.
25390 *
25391 *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
25392 *     will be associated by item identity in the array.
25393 *
25394 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
25395 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
25396 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
25397 *     element in the same way in the DOM.
25398 *
25399 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
25400 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
25401 *     property is same.
25402 *
25403 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
25404 *     to items in conjunction with a tracking expression.
25405 *
25406 * @example
25407 * This example initializes the scope to a list of names and
25408 * then uses `ngRepeat` to display every person:
25409  <example module="ngAnimate" deps="angular-animate.js" animations="true">
25410    <file name="index.html">
25411      <div ng-init="friends = [
25412        {name:'John', age:25, gender:'boy'},
25413        {name:'Jessie', age:30, gender:'girl'},
25414        {name:'Johanna', age:28, gender:'girl'},
25415        {name:'Joy', age:15, gender:'girl'},
25416        {name:'Mary', age:28, gender:'girl'},
25417        {name:'Peter', age:95, gender:'boy'},
25418        {name:'Sebastian', age:50, gender:'boy'},
25419        {name:'Erika', age:27, gender:'girl'},
25420        {name:'Patrick', age:40, gender:'boy'},
25421        {name:'Samantha', age:60, gender:'girl'}
25422      ]">
25423        I have {{friends.length}} friends. They are:
25424        <input type="search" ng-model="q" placeholder="filter friends..." />
25425        <ul class="example-animate-container">
25426          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
25427            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
25428          </li>
25429        </ul>
25430      </div>
25431    </file>
25432    <file name="animations.css">
25433      .example-animate-container {
25434        background:white;
25435        border:1px solid black;
25436        list-style:none;
25437        margin:0;
25438        padding:0 10px;
25439      }
25440
25441      .animate-repeat {
25442        line-height:40px;
25443        list-style:none;
25444        box-sizing:border-box;
25445      }
25446
25447      .animate-repeat.ng-move,
25448      .animate-repeat.ng-enter,
25449      .animate-repeat.ng-leave {
25450        -webkit-transition:all linear 0.5s;
25451        transition:all linear 0.5s;
25452      }
25453
25454      .animate-repeat.ng-leave.ng-leave-active,
25455      .animate-repeat.ng-move,
25456      .animate-repeat.ng-enter {
25457        opacity:0;
25458        max-height:0;
25459      }
25460
25461      .animate-repeat.ng-leave,
25462      .animate-repeat.ng-move.ng-move-active,
25463      .animate-repeat.ng-enter.ng-enter-active {
25464        opacity:1;
25465        max-height:40px;
25466      }
25467    </file>
25468    <file name="protractor.js" type="protractor">
25469      var friends = element.all(by.repeater('friend in friends'));
25470
25471      it('should render initial data set', function() {
25472        expect(friends.count()).toBe(10);
25473        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
25474        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
25475        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
25476        expect(element(by.binding('friends.length')).getText())
25477            .toMatch("I have 10 friends. They are:");
25478      });
25479
25480       it('should update repeater when filter predicate changes', function() {
25481         expect(friends.count()).toBe(10);
25482
25483         element(by.model('q')).sendKeys('ma');
25484
25485         expect(friends.count()).toBe(2);
25486         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
25487         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
25488       });
25489      </file>
25490    </example>
25491 */
25492var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
25493  var NG_REMOVED = '$$NG_REMOVED';
25494  var ngRepeatMinErr = minErr('ngRepeat');
25495  return {
25496    transclude: 'element',
25497    priority: 1000,
25498    terminal: true,
25499    $$tlb: true,
25500    link: function($scope, $element, $attr, ctrl, $transclude){
25501        var expression = $attr.ngRepeat;
25502        var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
25503          trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
25504          lhs, rhs, valueIdentifier, keyIdentifier,
25505          hashFnLocals = {$id: hashKey};
25506
25507        if (!match) {
25508          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
25509            expression);
25510        }
25511
25512        lhs = match[1];
25513        rhs = match[2];
25514        trackByExp = match[3];
25515
25516        if (trackByExp) {
25517          trackByExpGetter = $parse(trackByExp);
25518          trackByIdExpFn = function(key, value, index) {
25519            // assign key, value, and $index to the locals so that they can be used in hash functions
25520            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
25521            hashFnLocals[valueIdentifier] = value;
25522            hashFnLocals.$index = index;
25523            return trackByExpGetter($scope, hashFnLocals);
25524          };
25525        } else {
25526          trackByIdArrayFn = function(key, value) {
25527            return hashKey(value);
25528          };
25529          trackByIdObjFn = function(key) {
25530            return key;
25531          };
25532        }
25533
25534        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
25535        if (!match) {
25536          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
25537                                                                    lhs);
25538        }
25539        valueIdentifier = match[3] || match[1];
25540        keyIdentifier = match[2];
25541
25542        // Store a list of elements from previous run. This is a hash where key is the item from the
25543        // iterator, and the value is objects with following properties.
25544        //   - scope: bound scope
25545        //   - element: previous element.
25546        //   - index: position
25547        var lastBlockMap = {};
25548
25549        //watch props
25550        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
25551          var index, length,
25552              previousNode = $element[0],     // current position of the node
25553              nextNode,
25554              // Same as lastBlockMap but it has the current state. It will become the
25555              // lastBlockMap on the next iteration.
25556              nextBlockMap = {},
25557              arrayLength,
25558              childScope,
25559              key, value, // key/value of iteration
25560              trackById,
25561              trackByIdFn,
25562              collectionKeys,
25563              block,       // last object information {scope, element, id}
25564              nextBlockOrder = [],
25565              elementsToRemove;
25566
25567
25568          if (isArrayLike(collection)) {
25569            collectionKeys = collection;
25570            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
25571          } else {
25572            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
25573            // if object, extract keys, sort them and use to determine order of iteration over obj props
25574            collectionKeys = [];
25575            for (key in collection) {
25576              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
25577                collectionKeys.push(key);
25578              }
25579            }
25580            collectionKeys.sort();
25581          }
25582
25583          arrayLength = collectionKeys.length;
25584
25585          // locate existing items
25586          length = nextBlockOrder.length = collectionKeys.length;
25587          for(index = 0; index < length; index++) {
25588           key = (collection === collectionKeys) ? index : collectionKeys[index];
25589           value = collection[key];
25590           trackById = trackByIdFn(key, value, index);
25591           assertNotHasOwnProperty(trackById, '`track by` id');
25592           if(lastBlockMap.hasOwnProperty(trackById)) {
25593             block = lastBlockMap[trackById];
25594             delete lastBlockMap[trackById];
25595             nextBlockMap[trackById] = block;
25596             nextBlockOrder[index] = block;
25597           } else if (nextBlockMap.hasOwnProperty(trackById)) {
25598             // restore lastBlockMap
25599             forEach(nextBlockOrder, function(block) {
25600               if (block && block.scope) lastBlockMap[block.id] = block;
25601             });
25602             // This is a duplicate and we need to throw an error
25603             throw ngRepeatMinErr('dupes',
25604                  "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
25605                  expression, trackById, toJson(value));
25606           } else {
25607             // new never before seen block
25608             nextBlockOrder[index] = { id: trackById };
25609             nextBlockMap[trackById] = false;
25610           }
25611         }
25612
25613          // remove existing items
25614          for (key in lastBlockMap) {
25615            // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
25616            if (lastBlockMap.hasOwnProperty(key)) {
25617              block = lastBlockMap[key];
25618              elementsToRemove = getBlockElements(block.clone);
25619              $animate.leave(elementsToRemove);
25620              forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
25621              block.scope.$destroy();
25622            }
25623          }
25624
25625          // we are not using forEach for perf reasons (trying to avoid #call)
25626          for (index = 0, length = collectionKeys.length; index < length; index++) {
25627            key = (collection === collectionKeys) ? index : collectionKeys[index];
25628            value = collection[key];
25629            block = nextBlockOrder[index];
25630            if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
25631
25632            if (block.scope) {
25633              // if we have already seen this object, then we need to reuse the
25634              // associated scope/element
25635              childScope = block.scope;
25636
25637              nextNode = previousNode;
25638              do {
25639                nextNode = nextNode.nextSibling;
25640              } while(nextNode && nextNode[NG_REMOVED]);
25641
25642              if (getBlockStart(block) != nextNode) {
25643                // existing item which got moved
25644                $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
25645              }
25646              previousNode = getBlockEnd(block);
25647            } else {
25648              // new item which we don't know about
25649              childScope = $scope.$new();
25650            }
25651
25652            childScope[valueIdentifier] = value;
25653            if (keyIdentifier) childScope[keyIdentifier] = key;
25654            childScope.$index = index;
25655            childScope.$first = (index === 0);
25656            childScope.$last = (index === (arrayLength - 1));
25657            childScope.$middle = !(childScope.$first || childScope.$last);
25658            // jshint bitwise: false
25659            childScope.$odd = !(childScope.$even = (index&1) === 0);
25660            // jshint bitwise: true
25661
25662            if (!block.scope) {
25663              $transclude(childScope, function(clone) {
25664                clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
25665                $animate.enter(clone, null, jqLite(previousNode));
25666                previousNode = clone;
25667                block.scope = childScope;
25668                // Note: We only need the first/last node of the cloned nodes.
25669                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
25670                // by a directive with templateUrl when its template arrives.
25671                block.clone = clone;
25672                nextBlockMap[block.id] = block;
25673              });
25674            }
25675          }
25676          lastBlockMap = nextBlockMap;
25677        });
25678    }
25679  };
25680
25681  function getBlockStart(block) {
25682    return block.clone[0];
25683  }
25684
25685  function getBlockEnd(block) {
25686    return block.clone[block.clone.length - 1];
25687  }
25688}];
25689
25690/**
25691 * @ngdoc directive
25692 * @name ngShow
25693 *
25694 * @description
25695 * The `ngShow` directive shows or hides the given HTML element based on the expression
25696 * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
25697 * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
25698 * in AngularJS and sets the display style to none (using an !important flag).
25699 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
25700 *
25701 * ```html
25702 * <!-- when $scope.myValue is truthy (element is visible) -->
25703 * <div ng-show="myValue"></div>
25704 *
25705 * <!-- when $scope.myValue is falsy (element is hidden) -->
25706 * <div ng-show="myValue" class="ng-hide"></div>
25707 * ```
25708 *
25709 * When the `ngShow` expression evaluates to false then the `.ng-hide` CSS class is added to the class attribute
25710 * on the element causing it to become hidden. When true, the `.ng-hide` CSS class is removed
25711 * from the element causing the element not to appear hidden.
25712 *
25713 * <div class="alert alert-warning">
25714 * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
25715 * "f" / "0" / "false" / "no" / "n" / "[]"
25716 * </div>
25717 *
25718 * ## Why is !important used?
25719 *
25720 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
25721 * can be easily overridden by heavier selectors. For example, something as simple
25722 * as changing the display style on a HTML list item would make hidden elements appear visible.
25723 * This also becomes a bigger issue when dealing with CSS frameworks.
25724 *
25725 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
25726 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
25727 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
25728 *
25729 * ### Overriding `.ng-hide`
25730 *
25731 * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
25732 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
25733 * class in CSS:
25734 *
25735 * ```css
25736 * .ng-hide {
25737 *   //this is just another form of hiding an element
25738 *   display:block!important;
25739 *   position:absolute;
25740 *   top:-9999px;
25741 *   left:-9999px;
25742 * }
25743 * ```
25744 *
25745 * By default you don't need to override in CSS anything and the animations will work around the display style.
25746 *
25747 * ## A note about animations with `ngShow`
25748 *
25749 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
25750 * is true and false. This system works like the animation system present with ngClass except that
25751 * you must also include the !important flag to override the display property
25752 * so that you can perform an animation when the element is hidden during the time of the animation.
25753 *
25754 * ```css
25755 * //
25756 * //a working example can be found at the bottom of this page
25757 * //
25758 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
25759 *   transition:0.5s linear all;
25760 * }
25761 *
25762 * .my-element.ng-hide-add { ... }
25763 * .my-element.ng-hide-add.ng-hide-add-active { ... }
25764 * .my-element.ng-hide-remove { ... }
25765 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
25766 * ```
25767 *
25768 * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
25769 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
25770 *
25771 * @animations
25772 * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
25773 * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
25774 *
25775 * @element ANY
25776 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
25777 *     then the element is shown or hidden respectively.
25778 *
25779 * @example
25780  <example module="ngAnimate" deps="angular-animate.js" animations="true">
25781    <file name="index.html">
25782      Click me: <input type="checkbox" ng-model="checked"><br/>
25783      <div>
25784        Show:
25785        <div class="check-element animate-show" ng-show="checked">
25786          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
25787        </div>
25788      </div>
25789      <div>
25790        Hide:
25791        <div class="check-element animate-show" ng-hide="checked">
25792          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
25793        </div>
25794      </div>
25795    </file>
25796    <file name="glyphicons.css">
25797      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
25798    </file>
25799    <file name="animations.css">
25800      .animate-show {
25801        -webkit-transition:all linear 0.5s;
25802        transition:all linear 0.5s;
25803        line-height:20px;
25804        opacity:1;
25805        padding:10px;
25806        border:1px solid black;
25807        background:white;
25808      }
25809
25810      .animate-show.ng-hide {
25811        line-height:0;
25812        opacity:0;
25813        padding:0 10px;
25814      }
25815
25816      .check-element {
25817        padding:10px;
25818        border:1px solid black;
25819        background:white;
25820      }
25821    </file>
25822    <file name="protractor.js" type="protractor">
25823      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
25824      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
25825
25826      it('should check ng-show / ng-hide', function() {
25827        expect(thumbsUp.isDisplayed()).toBeFalsy();
25828        expect(thumbsDown.isDisplayed()).toBeTruthy();
25829
25830        element(by.model('checked')).click();
25831
25832        expect(thumbsUp.isDisplayed()).toBeTruthy();
25833        expect(thumbsDown.isDisplayed()).toBeFalsy();
25834      });
25835    </file>
25836  </example>
25837 */
25838var ngShowDirective = ['$animate', function($animate) {
25839  return function(scope, element, attr) {
25840    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
25841      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
25842    });
25843  };
25844}];
25845
25846
25847/**
25848 * @ngdoc directive
25849 * @name ngHide
25850 *
25851 * @description
25852 * The `ngHide` directive shows or hides the given HTML element based on the expression
25853 * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
25854 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
25855 * in AngularJS and sets the display style to none (using an !important flag).
25856 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
25857 *
25858 * ```html
25859 * <!-- when $scope.myValue is truthy (element is hidden) -->
25860 * <div ng-hide="myValue" class="ng-hide"></div>
25861 *
25862 * <!-- when $scope.myValue is falsy (element is visible) -->
25863 * <div ng-hide="myValue"></div>
25864 * ```
25865 *
25866 * When the `.ngHide` expression evaluates to true then the `.ng-hide` CSS class is added to the class attribute
25867 * on the element causing it to become hidden. When false, the `.ng-hide` CSS class is removed
25868 * from the element causing the element not to appear hidden.
25869 *
25870 * <div class="alert alert-warning">
25871 * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
25872 * "f" / "0" / "false" / "no" / "n" / "[]"
25873 * </div>
25874 *
25875 * ## Why is !important used?
25876 *
25877 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
25878 * can be easily overridden by heavier selectors. For example, something as simple
25879 * as changing the display style on a HTML list item would make hidden elements appear visible.
25880 * This also becomes a bigger issue when dealing with CSS frameworks.
25881 *
25882 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
25883 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
25884 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
25885 *
25886 * ### Overriding `.ng-hide`
25887 *
25888 * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
25889 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
25890 * class in CSS:
25891 *
25892 * ```css
25893 * .ng-hide {
25894 *   //this is just another form of hiding an element
25895 *   display:block!important;
25896 *   position:absolute;
25897 *   top:-9999px;
25898 *   left:-9999px;
25899 * }
25900 * ```
25901 *
25902 * By default you don't need to override in CSS anything and the animations will work around the display style.
25903 *
25904 * ## A note about animations with `ngHide`
25905 *
25906 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
25907 * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
25908 * CSS class is added and removed for you instead of your own CSS class.
25909 *
25910 * ```css
25911 * //
25912 * //a working example can be found at the bottom of this page
25913 * //
25914 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
25915 *   transition:0.5s linear all;
25916 * }
25917 *
25918 * .my-element.ng-hide-add { ... }
25919 * .my-element.ng-hide-add.ng-hide-add-active { ... }
25920 * .my-element.ng-hide-remove { ... }
25921 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
25922 * ```
25923 *
25924 * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
25925 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
25926 *
25927 * @animations
25928 * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
25929 * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
25930 *
25931 * @element ANY
25932 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
25933 *     the element is shown or hidden respectively.
25934 *
25935 * @example
25936  <example module="ngAnimate" deps="angular-animate.js" animations="true">
25937    <file name="index.html">
25938      Click me: <input type="checkbox" ng-model="checked"><br/>
25939      <div>
25940        Show:
25941        <div class="check-element animate-hide" ng-show="checked">
25942          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
25943        </div>
25944      </div>
25945      <div>
25946        Hide:
25947        <div class="check-element animate-hide" ng-hide="checked">
25948          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
25949        </div>
25950      </div>
25951    </file>
25952    <file name="glyphicons.css">
25953      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
25954    </file>
25955    <file name="animations.css">
25956      .animate-hide {
25957        -webkit-transition:all linear 0.5s;
25958        transition:all linear 0.5s;
25959        line-height:20px;
25960        opacity:1;
25961        padding:10px;
25962        border:1px solid black;
25963        background:white;
25964      }
25965
25966      .animate-hide.ng-hide {
25967        line-height:0;
25968        opacity:0;
25969        padding:0 10px;
25970      }
25971
25972      .check-element {
25973        padding:10px;
25974        border:1px solid black;
25975        background:white;
25976      }
25977    </file>
25978    <file name="protractor.js" type="protractor">
25979      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
25980      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
25981
25982      it('should check ng-show / ng-hide', function() {
25983        expect(thumbsUp.isDisplayed()).toBeFalsy();
25984        expect(thumbsDown.isDisplayed()).toBeTruthy();
25985
25986        element(by.model('checked')).click();
25987
25988        expect(thumbsUp.isDisplayed()).toBeTruthy();
25989        expect(thumbsDown.isDisplayed()).toBeFalsy();
25990      });
25991    </file>
25992  </example>
25993 */
25994var ngHideDirective = ['$animate', function($animate) {
25995  return function(scope, element, attr) {
25996    scope.$watch(attr.ngHide, function ngHideWatchAction(value){
25997      $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
25998    });
25999  };
26000}];
26001
26002/**
26003 * @ngdoc directive
26004 * @name ngStyle
26005 * @restrict AC
26006 *
26007 * @description
26008 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
26009 *
26010 * @element ANY
26011 * @param {expression} ngStyle
26012 *
26013 * {@link guide/expression Expression} which evals to an
26014 * object whose keys are CSS style names and values are corresponding values for those CSS
26015 * keys.
26016 *
26017 * Since some CSS style names are not valid keys for an object, they must be quoted.
26018 * See the 'background-color' style in the example below.
26019 *
26020 * @example
26021   <example>
26022     <file name="index.html">
26023        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
26024        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
26025        <input type="button" value="clear" ng-click="myStyle={}">
26026        <br/>
26027        <span ng-style="myStyle">Sample Text</span>
26028        <pre>myStyle={{myStyle}}</pre>
26029     </file>
26030     <file name="style.css">
26031       span {
26032         color: black;
26033       }
26034     </file>
26035     <file name="protractor.js" type="protractor">
26036       var colorSpan = element(by.css('span'));
26037
26038       it('should check ng-style', function() {
26039         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
26040         element(by.css('input[value=\'set color\']')).click();
26041         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
26042         element(by.css('input[value=clear]')).click();
26043         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
26044       });
26045     </file>
26046   </example>
26047 */
26048var ngStyleDirective = ngDirective(function(scope, element, attr) {
26049  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
26050    if (oldStyles && (newStyles !== oldStyles)) {
26051      forEach(oldStyles, function(val, style) { element.css(style, '');});
26052    }
26053    if (newStyles) element.css(newStyles);
26054  }, true);
26055});
26056
26057/**
26058 * @ngdoc directive
26059 * @name ngSwitch
26060 * @restrict EA
26061 *
26062 * @description
26063 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
26064 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
26065 * as specified in the template.
26066 *
26067 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
26068 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
26069 * matches the value obtained from the evaluated expression. In other words, you define a container element
26070 * (where you place the directive), place an expression on the **`on="..."` attribute**
26071 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
26072 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
26073 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
26074 * attribute is displayed.
26075 *
26076 * <div class="alert alert-info">
26077 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
26078 * as literal string values to match against.
26079 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
26079omeVal"` not against the
26080 * value of the expression `$scope.someVal`.
26081 * </div>
26082
26083 * @animations
26084 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
26085 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
26086 *
26087 * @usage
26088 *
26089 * ```
26090 * <ANY ng-switch="expression">
26091 *   <ANY ng-switch-when="matchValue1">...</ANY>
26092 *   <ANY ng-switch-when="matchValue2">...</ANY>
26093 *   <ANY ng-switch-default>...</ANY>
26094 * </ANY>
26095 * ```
26096 *
26097 *
26098 * @scope
26099 * @priority 800
26100 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
26101 * On child elements add:
26102 *
26103 * * `ngSwitchWhen`: the case statement to match against. If match then this
26104 *   case will be displayed. If the same match appears multiple times, all the
26105 *   elements will be displayed.
26106 * * `ngSwitchDefault`: the default case when no other case match. If there
26107 *   are multiple default cases, all of them will be displayed when no other
26108 *   case match.
26109 *
26110 *
26111 * @example
26112  <example module="switchExample" deps="angular-animate.js" animations="true">
26113    <file name="index.html">
26114      <div ng-controller="ExampleController">
26115        <select ng-model="selection" ng-options="item for item in items">
26116        </select>
26117        <tt>selection={{selection}}</tt>
26118        <hr/>
26119        <div class="animate-switch-container"
26120          ng-switch on="selection">
26121            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
26122            <div class="animate-switch" ng-switch-when="home">Home Span</div>
26123            <div class="animate-switch" ng-switch-default>default</div>
26124        </div>
26125      </div>
26126    </file>
26127    <file name="script.js">
26128      angular.module('switchExample', ['ngAnimate'])
26129        .controller('ExampleController', ['$scope', function($scope) {
26130          $scope.items = ['settings', 'home', 'other'];
26131          $scope.selection = $scope.items[0];
26132        }]);
26133    </file>
26134    <file name="animations.css">
26135      .animate-switch-container {
26136        position:relative;
26137        background:white;
26138        border:1px solid black;
26139        height:40px;
26140        overflow:hidden;
26141      }
26142
26143      .animate-switch {
26144        padding:10px;
26145      }
26146
26147      .animate-switch.ng-animate {
26148        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
26149        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
26150
26151        position:absolute;
26152        top:0;
26153        left:0;
26154        right:0;
26155        bottom:0;
26156      }
26157
26158      .animate-switch.ng-leave.ng-leave-active,
26159      .animate-switch.ng-enter {
26160        top:-50px;
26161      }
26162      .animate-switch.ng-leave,
26163      .animate-switch.ng-enter.ng-enter-active {
26164        top:0;
26165      }
26166    </file>
26167    <file name="protractor.js" type="protractor">
26168      var switchElem = element(by.css('[ng-switch]'));
26169      var select = element(by.model('selection'));
26170
26171      it('should start in settings', function() {
26172        expect(switchElem.getText()).toMatch(/Settings Div/);
26173      });
26174      it('should change to home', function() {
26175        select.all(by.css('option')).get(1).click();
26176        expect(switchElem.getText()).toMatch(/Home Span/);
26177      });
26178      it('should select default', function() {
26179        select.all(by.css('option')).get(2).click();
26180        expect(switchElem.getText()).toMatch(/default/);
26181      });
26182    </file>
26183  </example>
26184 */
26185var ngSwitchDirective = ['$animate', function($animate) {
26186  return {
26187    restrict: 'EA',
26188    require: 'ngSwitch',
26189
26190    // asks for $scope to fool the BC controller module
26191    controller: ['$scope', function ngSwitchController() {
26192     this.cases = {};
26193    }],
26194    link: function(scope, element, attr, ngSwitchController) {
26195      var watchExpr = attr.ngSwitch || attr.on,
26196          selectedTranscludes = [],
26197          selectedElements = [],
26198          previousElements = [],
26199          selectedScopes = [];
26200
26201      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
26202        var i, ii;
26203        for (i = 0, ii = previousElements.length; i < ii; ++i) {
26204          previousElements[i].remove();
26205        }
26206        previousElements.length = 0;
26207
26208        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
26209          var selected = selectedElements[i];
26210          selectedScopes[i].$destroy();
26211          previousElements[i] = selected;
26212          $animate.leave(selected, function() {
26213            previousElements.splice(i, 1);
26214          });
26215        }
26216
26217        selectedElements.length = 0;
26218        selectedScopes.length = 0;
26219
26220        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
26221          scope.$eval(attr.change);
26222          forEach(selectedTranscludes, function(selectedTransclude) {
26223            var selectedScope = scope.$new();
26224            selectedScopes.push(selectedScope);
26225            selectedTransclude.transclude(selectedScope, function(caseElement) {
26226              var anchor = selectedTransclude.element;
26227
26228              selectedElements.push(caseElement);
26229              $animate.enter(caseElement, anchor.parent(), anchor);
26230            });
26231          });
26232        }
26233      });
26234    }
26235  };
26236}];
26237
26238var ngSwitchWhenDirective = ngDirective({
26239  transclude: 'element',
26240  priority: 800,
26241  require: '^ngSwitch',
26242  link: function(scope, element, attrs, ctrl, $transclude) {
26243    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
26244    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
26245  }
26246});
26247
26248var ngSwitchDefaultDirective = ngDirective({
26249  transclude: 'element',
26250  priority: 800,
26251  require: '^ngSwitch',
26252  link: function(scope, element, attr, ctrl, $transclude) {
26253    ctrl.cases['?'] = (ctrl.cases['?'] || []);
26254    ctrl.cases['?'].push({ transclude: $transclude, element: element });
26255   }
26256});
26257
26258/**
26259 * @ngdoc directive
26260 * @name ngTransclude
26261 * @restrict AC
26262 *
26263 * @description
26264 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
26265 *
26266 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
26267 *
26268 * @element ANY
26269 *
26270 * @example
26271   <example module="transcludeExample">
26272     <file name="index.html">
26273       <script>
26274         angular.module('transcludeExample', [])
26275          .directive('pane', function(){
26276             return {
26277               restrict: 'E',
26278               transclude: true,
26279               scope: { title:'@' },
26280               template: '<div style="border: 1px solid black;">
26280' +
26281                           '<div style="background-color: gray">{{title}}</div>' +
26282                           '<div ng-transclude></div>' +
26283                         '</div>'
26284             };
26285         })
26286         .controller('ExampleController', ['$scope', function($scope) {
26287           $scope.title = 'Lorem Ipsum';
26288           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
26289         }]);
26290       </script>
26291       <div ng-controller="ExampleController">
26292         <input ng-model="title"><br>
26293         <textarea ng-model="text"></textarea> <br/>
26294         <pane title="{{title}}">{{text}}</pane>
26295       </div>
26296     </file>
26297     <file name="protractor.js" type="protractor">
26298        it('should have transcluded', function() {
26299          var titleElement = element(by.model('title'));
26300          titleElement.clear();
26301          titleElement.sendKeys('TITLE');
26302          var textElement = element(by.model('text'));
26303          textElement.clear();
26304          textElement.sendKeys('TEXT');
26305          expect(element(by.binding('title')).getText()).toEqual('TITLE');
26306          expect(element(by.binding('text')).getText()).toEqual('TEXT');
26307        });
26308     </file>
26309   </example>
26310 *
26311 */
26312var ngTranscludeDirective = ngDirective({
26313  link: function($scope, $element, $attrs, controller, $transclude) {
26314    if (!$transclude) {
26315      throw minErr('ngTransclude')('orphan',
26316       'Illegal use of ngTransclude directive in the template! ' +
26317       'No parent directive that requires a transclusion found. ' +
26318       'Element: {0}',
26319       startingTag($element));
26320    }
26321
26322    $transclude(function(clone) {
26323      $element.empty();
26324      $element.append(clone);
26325    });
26326  }
26327});
26328
26329/**
26330 * @ngdoc directive
26331 * @name script
26332 * @restrict E
26333 *
26334 * @description
26335 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
26336 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
26337 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
26338 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
26339 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
26340 *
26341 * @param {string} type Must be set to `'text/ng-template'`.
26342 * @param {string} id Cache name of the template.
26343 *
26344 * @example
26345  <example>
26346    <file name="index.html">
26347      <script type="text/ng-template" id="/tpl.html">
26348        Content of the template.
26349      </script>
26350
26351      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
26352      <div id="tpl-content" ng-include src="currentTpl"></div>
26353    </file>
26354    <file name="protractor.js" type="protractor">
26355      it('should load template defined inside script tag', function() {
26356        element(by.css('#tpl-link')).click();
26357        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
26358      });
26359    </file>
26360  </example>
26361 */
26362var scriptDirective = ['$templateCache', function($templateCache) {
26363  return {
26364    restrict: 'E',
26365    terminal: true,
26366    compile: function(element, attr) {
26367      if (attr.type == 'text/ng-template') {
26368        var templateUrl = attr.id,
26369            // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
26370            text = element[0].text;
26371
26372        $templateCache.put(templateUrl, text);
26373      }
26374    }
26375  };
26376}];
26377
26378var ngOptionsMinErr = minErr('ngOptions');
26379/**
26380 * @ngdoc directive
26381 * @name select
26382 * @restrict E
26383 *
26384 * @description
26385 * HTML `SELECT` element with angular data-binding.
26386 *
26387 * # `ngOptions`
26388 *
26389 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
26390 * elements for the `<select>` element using the array or object obtained by evaluating the
26391 * `ngOptions` comprehension_expression.
26392 *
26393 * When an item in the `<select>` menu is selected, the array element or object property
26394 * represented by the selected option will be bound to the model identified by the `ngModel`
26395 * directive.
26396 *
26397 * <div class="alert alert-warning">
26398 * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
26399 * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
26400 * </div>
26401 *
26402 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
26403 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
26404 * option. See example below for demonstration.
26405 *
26406 * <div class="alert alert-warning">
26407 * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
26408 * of {@link ng.directive:ngRepeat ngRepeat} when you want the
26409 * `select` model to be bound to a non-string value. This is because an option element can only
26410 * be bound to string values at present.
26411 * </div>
26412 *
26413 * @param {string} ngModel Assignable angular expression to data-bind to.
26414 * @param {string=} name Property name of the form under which the control is published.
26415 * @param {string=} required The control is considered valid only if value is entered.
26416 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26417 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26418 *    `required` when you want to data-bind to the `required` attribute.
26419 * @param {comprehension_expression=} ngOptions in one of the following forms:
26420 *
26421 *   * for array data sources:
26422 *     * `label` **`for`** `value` **`in`** `array`
26423 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
26424 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
26425 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26426 *   * for object data sources:
26427 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26428 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26429 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
26430 *     * `select` **`as`** `label` **`group by`** `group`
26431 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26432 *
26433 * Where:
26434 *
26435 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
26436 *   * `value`: local variable which will refer to each item in the `array` or each property value
26437 *      of `object` during iteration.
26438 *   * `key`: local variable which will refer to a property name in `object` during iteration.
26439 *   * `label`: The result of this expression will be the label for `<option>` element. The
26440 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
26441 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
26442 *      element. If not specified, `select` expression will default to `value`.
26443 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
26444 *      DOM element.
26445 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
26446 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
26447 *     `value` variable (e.g. `value.propertyName`).
26448 *
26449 * @example
26450    <example module="selectExample">
26451      <file name="index.html">
26452        <script>
26453        angular.module('selectExample', [])
26454          .controller('ExampleController', ['$scope', function($scope) {
26455            $scope.colors = [
26456              {name:'black', shade:'dark'},
26457              {name:'white', shade:'light'},
26458              {name:'red', shade:'dark'},
26459              {name:'blue', shade:'dark'},
26460              {name:'yellow', shade:'light'}
26461            ];
26462            $scope.myColor = $scope.colors[2]; // red
26463          }]);
26464        </script>
26465        <div ng-controller="ExampleController">
26466          <ul>
26467            <li ng-repeat="color in colors">
26468              Name: <input ng-model="color.name">
26469              [<a href ng-click="colors.splice($index, 1)">X</a>]
26470            </li>
26471            <li>
26472              [<a href ng-click="colors.push({})">add</a>]
26473            </li>
26474          </ul>
26475          <hr/>
26476          Color (null not allowed):
26477          <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
26478
26479          Color (null allowed):
26480          <span  class="nullable">
26481            <select ng-model="myColor" ng-options="color.name for color in colors">
26482              <option value="">-- choose color --</option>
26483            </select>
26484          </span><br/>
26485
26486          Color grouped by shade:
26487          <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
26488          </select><br/>
26489
26490
26491          Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
26492          <hr/>
26493          Currently selected: {{ {selected_color:myColor}  }}
26494          <div style="border:solid 1px black; height:20px"
26495               ng-style="{'background-color':myColor.name}">
26496          </div>
26497        </div>
26498      </file>
26499      <file name="protractor.js" type="protractor">
26500         it('should check ng-options', function() {
26501           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
26502           element.all(by.model('myColor')).first().click();
26503           element.all(by.css('select[ng-model="myColor"] option')).first().click();
26504           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
26505           element(by.css('.nullable select[ng-model="myColor"]')).click();
26506           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
26507           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
26508         });
26509      </file>
26510    </example>
26511 */
26512
26513var ngOptionsDirective = valueFn({ terminal: true });
26514// jshint maxlen: false
26515var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
26516                         //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
26517  var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
26518      nullModelCtrl = {$setViewValue: noop};
26519// jshint maxlen: 100
26520
26521  return {
26522    restrict: 'E',
26523    require: ['select', '?ngModel'],
26524    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
26525      var self = this,
26526          optionsMap = {},
26527          ngModelCtrl = nullModelCtrl,
26528          nullOption,
26529          unknownOption;
26530
26531
26532      self.databound = $attrs.ngModel;
26533
26534
26535      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
26536        ngModelCtrl = ngModelCtrl_;
26537        nullOption = nullOption_;
26538        unknownOption = unknownOption_;
26539      };
26540
26541
26542      self.addOption = function(value) {
26543        assertNotHasOwnProperty(value, '"option value"');
26544        optionsMap[value] = true;
26545
26546        if (ngModelCtrl.$viewValue == value) {
26547          $element.val(value);
26548          if (unknownOption.parent()) unknownOption.remove();
26549        }
26550      };
26551
26552
26553      self.removeOption = function(value) {
26554        if (this.hasOption(value)) {
26555          delete optionsMap[value];
26556          if (ngModelCtrl.$viewValue == value) {
26557            this.renderUnknownOption(value);
26558          }
26559        }
26560      };
26561
26562
26563      self.renderUnknownOption = function(val) {
26564        var unknownVal = '? ' + hashKey(val) + ' ?';
26565        unknownOption.val(unknownVal);
26566        $element.prepend(unknownOption);
26567        $element.val(unknownVal);
26568        unknownOption.prop('selected', true); // needed for IE
26569      };
26570
26571
26572      self.hasOption = function(value) {
26573        return optionsMap.hasOwnProperty(value);
26574      };
26575
26576      $scope.$on('$destroy', function() {
26577        // disable unknown option so that we don't do work when the whole select is being destroyed
26578        self.renderUnknownOption = noop;
26579      });
26580    }],
26581
26582    link: function(scope, element, attr, ctrls) {
26583      // if ngModel is not defined, we don't need to do anything
26584      if (!ctrls[1]) return;
26585
26586      var selectCtrl = ctrls[0],
26587          ngModelCtrl = ctrls[1],
26588          multiple = attr.multiple,
26589          optionsExp = attr.ngOptions,
26590          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
26591          emptyOption,
26592          // we can't just jqLite('<option>') since jqLite is not smart enough
26593          // to create it in <select> and IE barfs otherwise.
26594          optionTemplate = jqLite(document.createElement('option')),
26595          optGroupTemplate =jqLite(document.createElement('optgroup')),
26596          unknownOption = optionTemplate.clone();
26597
26598      // find "null" option
26599      for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
26600        if (children[i].value === '') {
26601          emptyOption = nullOption = children.eq(i);
26602          break;
26603        }
26604      }
26605
26606      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
26607
26608      // required validator
26609      if (multiple) {
26610        ngModelCtrl.$isEmpty = function(value) {
26611          return !value || value.length === 0;
26612        };
26613      }
26614
26615      if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
26616      else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
26617      else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
26618
26619
26620      ////////////////////////////
26621
26622
26623
26624      function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
26625        ngModelCtrl.$render = function() {
26626          var viewValue = ngModelCtrl.$viewValue;
26627
26628          if (selectCtrl.hasOption(viewValue)) {
26629            if (unknownOption.parent()) unknownOption.remove();
26630            selectElement.val(viewValue);
26631            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
26632          } else {
26633            if (isUndefined(viewValue) && emptyOption) {
26634              selectElement.val('');
26635            } else {
26636              selectCtrl.renderUnknownOption(viewValue);
26637            }
26638          }
26639        };
26640
26641        selectElement.on('change', function() {
26642          scope.$apply(function() {
26643            if (unknownOption.parent()) unknownOption.remove();
26644            ngModelCtrl.$setViewValue(selectElement.val());
26645          });
26646        });
26647      }
26648
26649      function setupAsMultiple(scope, selectElement, ctrl) {
26650        var lastView;
26651        ctrl.$render = function() {
26652          var items = new HashMap(ctrl.$viewValue);
26653          forEach(selectElement.find('option'), function(option) {
26654            option.selected = isDefined(items.get(option.value));
26655          });
26656        };
26657
26658        // we have to do it on each watch since ngModel watches reference, but
26659        // we need to work of an array, so we need to see if anything was inserted/removed
26660        scope.$watch(function selectMultipleWatch() {
26661          if (!equals(lastView, ctrl.$viewValue)) {
26662            lastView = shallowCopy(ctrl.$viewValue);
26663            ctrl.$render();
26664          }
26665        });
26666
26667        selectElement.on('change', function() {
26668          scope.$apply(function() {
26669            var array = [];
26670            forEach(selectElement.find('option'), function(option) {
26671              if (option.selected) {
26672                array.push(option.value);
26673              }
26674            });
26675            ctrl.$setViewValue(array);
26676          });
26677        });
26678      }
26679
26680      function setupAsOptions(scope, selectElement, ctrl) {
26681        var match;
26682
26683        if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
26684          throw ngOptionsMinErr('iexp',
26685            "Expected expression in form of " +
26686            "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
26687            " but got '{0}'. Element: {1}",
26688            optionsExp, startingTag(selectElement));
26689        }
26690
26691        var displayFn = $parse(match[2] || match[1]),
26692            valueName = match[4] || match[6],
26693            keyName = match[5],
26694            groupByFn = $parse(match[3] || ''),
26695            valueFn = $parse(match[2] ? match[1] : valueName),
26696            valuesFn = $parse(match[7]),
26697            track = match[8],
26698            trackFn = track ? $parse(match[8]) : null,
26699            // This is an array of array of existing option groups in DOM.
26700            // We try to reuse these if possible
26701            // - optionGroupsCache[0] is the options with no option group
26702            // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
26703            optionGroupsCache = [[{element: selectElement, label:''}]];
26704
26705        if (nullOption) {
26706          // compile the element since there might be bindings in it
26707          $compile(nullOption)(scope);
26708
26709          // remove the class, which is added automatically because we recompile the element and it
26710          // becomes the compilation root
26711          nullOption.removeClass('ng-scope');
26712
26713          // we need to remove it before calling selectElement.empty() because otherwise IE will
26714          // remove the label from the element. wtf?
26715          nullOption.remove();
26716        }
26717
26718        // clear contents, we'll add what's needed based on the model
26719        selectElement.empty();
26720
26721        selectElement.on('change', function() {
26722          scope.$apply(function() {
26723            var optionGroup,
26724                collection = valuesFn(scope) || [],
26725                locals = {},
26726                key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
26727
26728            if (multiple) {
26729              value = [];
26730              for (groupIndex = 0, groupLength = optionGroupsCache.length;
26731                   groupIndex < groupLength;
26732                   groupIndex++) {
26733                // list of options for that group. (first item has the parent)
26734                optionGroup = optionGroupsCache[groupIndex];
26735
26736                for(index = 1, length = optionGroup.length; index < length; index++) {
26737                  if ((optionElement = optionGroup[index].element)[0].selected) {
26738                    key = optionElement.val();
26739                    if (keyName) locals[keyName] = key;
26740                    if (trackFn) {
26741                      for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
26742                        locals[valueName] = collection[trackIndex];
26743                        if (trackFn(scope, locals) == key) break;
26744                      }
26745                    } else {
26746                      locals[valueName] = collection[key];
26747                    }
26748                    value.push(valueFn(scope, locals));
26749                  }
26750                }
26751              }
26752            } else {
26753              key = selectElement.val();
26754              if (key == '?') {
26755                value = undefined;
26756              } else if (key === ''){
26757                value = null;
26758              } else {
26759                if (trackFn) {
26760                  for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
26761                    locals[valueName] = collection[trackIndex];
26762                    if (trackFn(scope, locals) == key) {
26763                      value = valueFn(scope, locals);
26764                      break;
26765                    }
26766                  }
26767                } else {
26768                  locals[valueName] = collection[key];
26769                  if (keyName) locals[keyName] = key;
26770                  value = valueFn(scope, locals);
26771                }
26772              }
26773            }
26774            ctrl.$setViewValue(value);
26775            render();
26776          });
26777        });
26778
26779        ctrl.$render = render;
26780
26781        scope.$watchCollection(valuesFn, render);
26782        scope.$watchCollection(function () {
26783          var locals = {},
26784              values = valuesFn(scope);
26785          if (values) {
26786            var toDisplay = new Array(values.length);
26787            for (var i = 0, ii = values.length; i < ii; i++) {
26788              locals[valueName] = values[i];
26789              toDisplay[i] = displayFn(scope, locals);
26790            }
26791            return toDisplay;
26792          }
26793        }, render);
26794
26795        if ( multiple ) {
26796          scope.$watchCollection(function() { return ctrl.$modelValue; }, render);
26797        }
26798
26799        function getSelectedSet() {
26800          var selectedSet = false;
26801          if (multiple) {
26802            var modelValue = ctrl.$modelValue;
26803            if (trackFn && isArray(modelValue)) {
26804              selectedSet = new HashMap([]);
26805              var locals = {};
26806              for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
26807                locals[valueName] = modelValue[trackIndex];
26808                selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
26809              }
26810            } else {
26811              selectedSet = new HashMap(modelValue);
26812            }
26813          }
26814          return selectedSet;
26815        }
26816
26817
26818        function render() {
26819              // Temporary location for the option groups before we render them
26820          var optionGroups = {'':[]},
26821              optionGroupNames = [''],
26822              optionGroupName,
26823              optionGroup,
26824              option,
26825              existingParent, existingOptions, existingOption,
26826              modelValue = ctrl.$modelValue,
26827              values = valuesFn(scope) || [],
26828              keys = keyName ? sortedKeys(values) : values,
26829              key,
26830              groupLength, length,
26831              groupIndex, index,
26832              locals = {},
26833              selected,
26834              selectedSet = getSelectedSet(),
26835              lastElement,
26836              element,
26837              label;
26838
26839
26840          // We now build up the list of options we need (we merge later)
26841          for (index = 0; length = keys.length, index < length; index++) {
26842
26843            key = index;
26844            if (keyName) {
26845              key = keys[index];
26846              if ( key.charAt(0) === '$' ) continue;
26847              locals[keyName] = key;
26848            }
26849
26850            locals[valueName] = values[key];
26851
26852            optionGroupName = groupByFn(scope, locals) || '';
26853            if (!(optionGroup = optionGroups[optionGroupName])) {
26854              optionGroup = optionGroups[optionGroupName] = [];
26855              optionGroupNames.push(optionGroupName);
26856            }
26857            if (multiple) {
26858              selected = isDefined(
26859                selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
26860              );
26861            } else {
26862              if (trackFn) {
26863                var modelCast = {};
26864                modelCast[valueName] = modelValue;
26865                selected = trackFn(scope, modelCast) === trackFn(scope, locals);
26866              } else {
26867                selected = modelValue === valueFn(scope, locals);
26868              }
26869              selectedSet = selectedSet || selected; // see if at least one item is selected
26870            }
26871            label = displayFn(scope, locals); // what will be seen by the user
26872
26873            // doing displayFn(scope, locals) || '' overwrites zero values
26874            label = isDefined(label) ? label : '';
26875            optionGroup.push({
26876              // either the index into array or key from object
26877              id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
26878              label: label,
26879              selected: selected                   // determine if we should be selected
26880            });
26881          }
26882          if (!multiple) {
26883            if (nullOption || modelValue === null) {
26884              // insert null option if we have a placeholder, or the model is null
26885              optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
26886            } else if (!selectedSet) {
26887              // option could not be found, we have to insert the undefined item
26888              optionGroups[''].unshift({id:'?', label:'', selected:true});
26889            }
26890          }
26891
26892          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
26893          for (groupIndex = 0, groupLength = optionGroupNames.length;
26894               groupIndex < groupLength;
26895               groupIndex++) {
26896            // current option group name or '' if no group
26897            optionGroupName = optionGroupNames[groupIndex];
26898
26899            // list of options for that group. (first item has the parent)
26900            optionGroup = optionGroups[optionGroupName];
26901
26902            if (optionGroupsCache.length <= groupIndex) {
26903              // we need to grow the optionGroups
26904              existingParent = {
26905                element: optGroupTemplate.clone().attr('label', optionGroupName),
26906                label: optionGroup.label
26907              };
26908              existingOptions = [existingParent];
26909              optionGroupsCache.push(existingOptions);
26910              selectElement.append(existingParent.element);
26911            } else {
26912              existingOptions = optionGroupsCache[groupIndex];
26913              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
26914
26915              // update the OPTGROUP label if not the same.
26916              if (existingParent.label != optionGroupName) {
26917                existingParent.element.attr('label', existingParent.label = optionGroupName);
26918              }
26919            }
26920
26921            lastElement = null;  // start at the beginning
26922            for(index = 0, length = optionGroup.length; index < length; index++) {
26923              option = optionGroup[index];
26924              if ((existingOption = existingOptions[index+1])) {
26925                // reuse elements
26926                lastElement = existingOption.element;
26927                if (existingOption.label !== option.label) {
26928                  lastElement.text(existingOption.label = option.label);
26929                }
26930                if (existingOption.id !== option.id) {
26931                  lastElement.val(existingOption.id = option.id);
26932                }
26933                // lastElement.prop('selected') provided by jQuery has side-effects
26934                if (lastElement[0].selected !== option.selected) {
26935                  lastElement.prop('selected', (existingOption.selected = option.selected));
26936                  if (msie) {
26937                    // See #7692
26938                    // The selected item wouldn't visually update on IE without this.
26939                    // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
26940                    lastElement.prop('selected', existingOption.selected);
26941                  }
26942                }
26943              } else {
26944                // grow elements
26945
26946                // if it's a null option
26947                if (option.id === '' && nullOption) {
26948                  // put back the pre-compiled element
26949                  element = nullOption;
26950                } else {
26951                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
26952                  // in this version of jQuery on some browser the .text() returns a string
26953                  // rather then the element.
26954                  (element = optionTemplate.clone())
26955                      .val(option.id)
26956                      .prop('selected', option.selected)
26957                      .attr('selected', option.selected)
26958                      .text(option.label);
26959                }
26960
26961                existingOptions.push(existingOption = {
26962                    element: element,
26963                    label: option.label,
26964                    id: option.id,
26965                    selected: option.selected
26966                });
26967                if (lastElement) {
26968                  lastElement.after(element);
26969                } else {
26970                  existingParent.element.append(element);
26971                }
26972                lastElement = element;
26973              }
26974            }
26975            // remove any excessive OPTIONs in a group
26976            index++; // increment since the existingOptions[0] is parent element not OPTION
26977            while(existingOptions.length > index) {
26978              existingOptions.pop().element.remove();
26979            }
26980          }
26981          // remove any excessive OPTGROUPs from select
26982          while(optionGroupsCache.length > groupIndex) {
26983            optionGroupsCache.pop()[0].element.remove();
26984          }
26985        }
26986      }
26987    }
26988  };
26989}];
26990
26991var optionDirective = ['$interpolate', function($interpolate) {
26992  var nullSelectCtrl = {
26993    addOption: noop,
26994    removeOption: noop
26995  };
26996
26997  return {
26998    restrict: 'E',
26999    priority: 100,
27000    compile: function(element, attr) {
27001      if (isUndefined(attr.value)) {
27002        var interpolateFn = $interpolate(element.text(), true);
27003        if (!interpolateFn) {
27004          attr.$set('value', element.text());
27005        }
27006      }
27007
27008      return function (scope, element, attr) {
27009        var selectCtrlName = '$selectController',
27010            parent = element.parent(),
27011            selectCtrl = parent.data(selectCtrlName) ||
27012              parent.parent().data(selectCtrlName); // in case we are in optgroup
27013
27014        if (selectCtrl && selectCtrl.databound) {
27015          // For some reason Opera defaults to true and if not overridden this messes up the repeater.
27016          // We don't want the view to drive the initialization of the model anyway.
27017          element.prop('selected', false);
27018        } else {
27019          selectCtrl = nullSelectCtrl;
27020        }
27021
27022        if (interpolateFn) {
27023          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
27024            attr.$set('value', newVal);
27025            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
27026            selectCtrl.addOption(newVal);
27027          });
27028        } else {
27029          selectCtrl.addOption(attr.value);
27030        }
27031
27032        element.on('$destroy', function() {
27033          selectCtrl.removeOption(attr.value);
27034        });
27035      };
27036    }
27037  };
27038}];
27039
27040var styleDirective = valueFn({
27041  restrict: 'E',
27042  terminal: true
27043});
27044
27045  if (window.angular.bootstrap) {
27046    //AngularJS is already loaded, so we can return here...
27047    console.log('WARNING: Tried to load angular more than once.');
27048    return;
27049  }
27050
27051  //try to bind to jquery now so that one can write angular.element().read()
27052  //but we will rebind on bootstrap again.
27053  bindJQuery();
27054
27055  publishExternalAPI(angular);
27056
27057  jqLite(document).ready(function() {
27058    angularInit(document, bootstrap);
27059  });
27060
27061})(window, document);
27062
27063!window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}.ng-hide-add-active,.ng-hide-remove{display:block!important;}</style>');
27064/**
27065 * @license AngularJS v1.2.25
27066 * (c) 2010-2014 Google, Inc. http://angularjs.org
27067 * License: MIT
27068 */
27069(function(window, angular, undefined) {'use strict';
27070
27071/* jshint maxlen: false */
27072
27073/**
27074 * @ngdoc module
27075 * @name ngAnimate
27076 * @description
27077 *
27078 * # ngAnimate
27079 *
27080 * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
27081 *
27082 *
27083 * <div doc-module-components="ngAnimate"></div>
27084 *
27085 * # Usage
27086 *
27087 * To see animations in action, all that is required is to define the appropriate CSS classes
27088 * or to register a JavaScript animation via the myModule.animation() function. The directives that support animation automatically are:
27089 * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation
27090 * by using the `$animate` service.
27091 *
27092 * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
27093 *
27094 * | Directive                                                 | Supported Animations                               |
27095 * |---------------------------------------------------------- |----------------------------------------------------|
27096 * | {@link ng.directive:ngRepeat#usage_animations ngRepeat}         | enter, leave and move                              |
27097 * | {@link ngRoute.directive:ngView#usage_animations ngView}        | enter and leave                                    |
27098 * | {@link ng.directive:ngInclude#usage_animations ngInclude}       | enter and leave                                    |
27099 * | {@link ng.directive:ngSwitch#usage_animations ngSwitch}         | enter and leave                                    |
27100 * | {@link ng.directive:ngIf#usage_animations ngIf}                 | enter and leave                                    |
27101 * | {@link ng.directive:ngClass#usage_animations ngClass}           | add and remove                                     |
27102 * | {@link ng.directive:ngShow#usage_animations ngShow & ngHide}    | add and remove (the ng-hide class value)           |
27103 * | {@link ng.directive:form#usage_animations form}
27103                 | add and remove (dirty, pristine, valid, invalid & all other validations)                |
27104 * | {@link ng.directive:ngModel#usage_animations ngModel}           | add and remove (dirty, pristine, valid, invalid & all other validations)                |
27105 *
27106 * You can find out more information about animations upon visiting each directive page.
27107 *
27108 * Below is an example of how to apply animations to a directive that supports animation hooks:
27109 *
27110 * ```html
27111 * <style type="text/css">
27112 * .slide.ng-enter, .slide.ng-leave {
27113 *   -webkit-transition:0.5s linear all;
27114 *   transition:0.5s linear all;
27115 * }
27116 *
27117 * .slide.ng-enter { }        /&#42; starting animations for enter &#42;/
27118 * .slide.ng-enter.ng-enter-active { } /&#42; terminal animations for enter &#42;/
27119 * .slide.ng-leave { }        /&#42; starting animations for leave &#42;/
27120 * .slide.ng-leave.ng-leave-active { } /&#42; terminal animations for leave &#42;/
27121 * </style>
27122 *
27123 * <!--
27124 * the animate service will automatically add .ng-enter and .ng-leave to the element
27125 * to trigger the CSS transition/animations
27126 * -->
27127 * <ANY class="slide" ng-include="..."></ANY>
27128 * ```
27129 *
27130 * Keep in mind that, by default, if an animation is running, any child elements cannot be animated
27131 * until the parent element's animation has completed. This blocking feature can be overridden by
27132 * placing the `ng-animate-children` attribute on a parent container tag.
27133 *
27134 * ```html
27135 * <div class="slide-animation" ng-if="on" ng-animate-children>
27136 *   <div class="fade-animation" ng-if="on">
27137 *     <div class="explode-animation" ng-if="on">
27138 *        ...
27139 *     </div>
27140 *   </div>
27141 * </div>
27142 * ```
27143 *
27144 * When the `on` expression value changes and an animation is triggered then each of the elements within
27145 * will all animate without the block being applied to child elements.
27146 *
27147 * <h2>CSS-defined Animations</h2>
27148 * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
27149 * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported
27150 * and can be used to play along with this naming structure.
27151 *
27152 * The following code below demonstrates how to perform animations using **CSS transitions** with Angular:
27153 *
27154 * ```html
27155 * <style type="text/css">
27156 * /&#42;
27157 *  The animate class is apart of the element and the ng-enter class
27158 *  is attached to the element once the enter animation event is triggered
27159 * &#42;/
27160 * .reveal-animation.ng-enter {
27161 *  -webkit-transition: 1s linear all; /&#42; Safari/Chrome &#42;/
27162 *  transition: 1s linear all; /&#42; All other modern browsers and IE10+ &#42;/
27163 *
27164 *  /&#42; The animation preparation code &#42;/
27165 *  opacity: 0;
27166 * }
27167 *
27168 * /&#42;
27169 *  Keep in mind that you want to combine both CSS
27170 *  classes together to avoid any CSS-specificity
27171 *  conflicts
27172 * &#42;/
27173 * .reveal-animation.ng-enter.ng-enter-active {
27174 *  /&#42; The animation code itself &#42;/
27175 *  opacity: 1;
27176 * }
27177 * </style>
27178 *
27179 * <div class="view-container">
27180 *   <div ng-view class="reveal-animation"></div>
27181 * </div>
27182 * ```
27183 *
27184 * The following code below demonstrates how to perform animations using **CSS animations** with Angular:
27185 *
27186 * ```html
27187 * <style type="text/css">
27188 * .reveal-animation.ng-enter {
27189 *   -webkit-animation: enter_sequence 1s linear; /&#42; Safari/Chrome &#42;/
27190 *   animation: enter_sequence 1s linear; /&#42; IE10+ and Future Browsers &#42;/
27191 * }
27192 * @-webkit-keyframes enter_sequence {
27193 *   from { opacity:0; }
27194 *   to { opacity:1; }
27195 * }
27196 * @keyframes enter_sequence {
27197 *   from { opacity:0; }
27198 *   to { opacity:1; }
27199 * }
27200 * </style>
27201 *
27202 * <div class="view-container">
27203 *   <div ng-view class="reveal-animation"></div>
27204 * </div>
27205 * ```
27206 *
27207 * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing.
27208 *
27209 * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add
27210 * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically
27211 * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be
27212 * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end
27213 * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element
27214 * has no CSS transition/animation classes applied to it.
27215 *
27216 * <h3>CSS Staggering Animations</h3>
27217 * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
27218 * curtain-like effect. The ngAnimate module, as of 1.2.0, supports staggering animations and the stagger effect can be
27219 * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
27220 * the animation. The style property expected within the stagger class can either be a **transition-delay** or an
27221 * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).
27222 *
27223 * ```css
27224 * .my-animation.ng-enter {
27225 *   /&#42; standard transition code &#42;/
27226 *   -webkit-transition: 1s linear all;
27227 *   transition: 1s linear all;
27228 *   opacity:0;
27229 * }
27230 * .my-animation.ng-enter-stagger {
27231 *   /&#42; this will have a 100ms delay between each successive leave animation &#42;/
27232 *   -webkit-transition-delay: 0.1s;
27233 *   transition-delay: 0.1s;
27234 *
27235 *   /&#42; in case the stagger doesn't work then these two values
27236 *    must be set to 0 to avoid an accidental CSS inheritance &#42;/
27237 *   -webkit-transition-duration: 0s;
27238 *   transition-duration: 0s;
27239 * }
27240 * .my-animation.ng-enter.ng-enter-active {
27241 *   /&#42; standard transition styles &#42;/
27242 *   opacity:1;
27243 * }
27244 * ```
27245 *
27246 * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations
27247 * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this
27248 * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation
27249 * will also be reset if more than 10ms has passed after the last animation has been fired.
27250 *
27251 * The following code will issue the **ng-leave-stagger** event on the element provided:
27252 *
27253 * ```js
27254 * var kids = parent.children();
27255 *
27256 * $animate.leave(kids[0]); //stagger index=0
27257 * $animate.leave(kids[1]); //stagger index=1
27258 * $animate.leave(kids[2]); //stagger index=2
27259 * $animate.leave(kids[3]); //stagger index=3
27260 * $animate.leave(kids[4]); //stagger index=4
27261 *
27262 * $timeout(function() {
27263 *   //stagger has reset itself
27264 *   $animate.leave(kids[5]); //stagger index=0
27265 *   $animate.leave(kids[6]); //stagger index=1
27266 * }, 100, false);
27267 * ```
27268 *
27269 * Stagger animations are currently only supported within CSS-defined animations.
27270 *
27271 * <h2>JavaScript-defined Animations</h2>
27272 * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not
27273 * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module.
27274 *
27275 * ```js
27276 * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application.
27277 * var ngModule = angular.module('YourApp', ['ngAnimate']);
27278 * ngModule.animation('.my-crazy-animation', function() {
27279 *   return {
27280 *     enter: function(element, done) {
27281 *       //run the animation here and call done when the animation is complete
27282 *       return function(cancelled) {
27283 *         //this (optional) function will be called when the animation
27284 *         //completes or when the animation is cancelled (the cancelled
27285 *         //flag will be set to true if cancelled).
27286 *       };
27287 *     },
27288 *     leave: function(element, done) { },
27289 *     move: function(element, done) { },
27290 *
27291 *     //animation that can be triggered before the class is added
27292 *     beforeAddClass: function(element, className, done) { },
27293 *
27294 *     //animation that can be triggered after the class is added
27295 *     addClass: function(element, className, done) { },
27296 *
27297 *     //animation that can be triggered before the class is removed
27298 *     beforeRemoveClass: function(element, className, done) { },
27299 *
27300 *     //animation that can be triggered after the class is removed
27301 *     removeClass: function(element, className, done) { }
27302 *   };
27303 * });
27304 * ```
27305 *
27306 * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run
27307 * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
27308 * the element's CSS class attribute value and then run the matching animation event function (if found).
27309 * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will
27310 * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported).
27311 *
27312 * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
27313 * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run,
27314 * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation
27315 * or transition code that is defined via a stylesheet).
27316 *
27317 */
27318
27319angular.module('ngAnimate', ['ng'])
27320
27321  /**
27322   * @ngdoc provider
27323   * @name $animateProvider
27324   * @description
27325   *
27326   * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module.
27327   * When an animation is triggered, the $animate service will query the $animate service to find any animations that match
27328   * the provided name value.
27329   *
27330   * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
27331   *
27332   * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
27333   *
27334   */
27335  .directive('ngAnimateChildren', function() {
27336    var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
27337    return function(scope, element, attrs) {
27338      var val = attrs.ngAnimateChildren;
27339      if(angular.isString(val) && val.length === 0) { //empty attribute
27340        element.data(NG_ANIMATE_CHILDREN, true);
27341      } else {
27342        scope.$watch(val, function(value) {
27343          element.data(NG_ANIMATE_CHILDREN, !!value);
27344        });
27345      }
27346    };
27347  })
27348
27349  //this private service is only used within CSS-enabled animations
27350  //IE8 + IE9 do not support rAF natively, but that is fine since they
27351  //also don't support transitions and keyframes which means that the code
27352  //below will never be used by the two browsers.
27353  .factory('$$animateReflow', ['$$rAF', '$document', function($$rAF, $document) {
27354    var bod = $document[0].body;
27355    return function(fn) {
27356      //the returned function acts as the cancellation function
27357      return $$rAF(function() {
27358        //the line below will force the browser to perform a repaint
27359        //so that all the animated elements within the animation frame
27360        //will be properly updated and drawn on screen. This is
27361        //required to perform multi-class CSS based animations with
27362        //Firefox. DO NOT REMOVE THIS LINE.
27363        var a = bod.offsetWidth + 1;
27364        fn();
27365      });
27366    };
27367  }])
27368
27369  .config(['$provide', '$animateProvider', function($provide, $animateProvider) {
27370    var noop = angular.noop;
27371    var forEach = angular.forEach;
27372    var selectors = $animateProvider.$$selectors;
27373
27374    var ELEMENT_NODE = 1;
27375    var NG_ANIMATE_STATE = '$$ngAnimateState';
27376    var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
27377    var NG_ANIMATE_CLASS_NAME = 'ng-animate';
27378    var rootAnimateState = {running: true};
27379
27380    function extractElementNode(element) {
27381      for(var i = 0; i < element.length; i++) {
27382        var elm = element[i];
27383        if(elm.nodeType == ELEMENT_NODE) {
27384          return elm;
27385        }
27386      }
27387    }
27388
27389    function prepareElement(element) {
27390      return element && angular.element(element);
27391    }
27392
27393    function stripCommentsFromElement(element) {
27394      return angular.element(extractElementNode(element));
27395    }
27396
27397    function isMatchingElement(elm1, elm2) {
27398      return extractElementNode(elm1) == extractElementNode(elm2);
27399    }
27400
27401    $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document',
27402                            function($delegate,   $injector,   $sniffer,   $rootElement,   $$asyncCallback,    $rootScope,   $document) {
27403
27404      var globalAnimationCounter = 0;
27405      $rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
27406
27407      // disable animations during bootstrap, but once we bootstrapped, wait again
27408      // for another digest until enabling animations. The reason why we digest twice
27409      // is because all structural animations (enter, leave and move) all perform a
27410      // post digest operation before animating. If we only wait for a single digest
27411      // to pass then the structural animation would render its animation on page load.
27412      // (which is what we're trying to avoid when the application first boots up.)
27413      $rootScope.$$postDigest(function() {
27414        $rootScope.$$postDigest(function() {
27415          rootAnimateState.running = false;
27416        });
27417      });
27418
27419      var classNameFilter = $animateProvider.classNameFilter();
27420      var isAnimatableClassName = !classNameFilter
27421              ? function() { return true; }
27422              : function(className) {
27423                return classNameFilter.test(className);
27424              };
27425
27426      function blockElementAnimations(element) {
27427        var data = element.data(NG_ANIMATE_STATE) || {};
27428        data.running = true;
27429        element.data(NG_ANIMATE_STATE, data);
27430      }
27431
27432      function lookup(name) {
27433        if (name) {
27434          var matches = [],
27435              flagMap = {},
27436              classes = name.substr(1).split('.');
27437
27438          //the empty string value is the default animation
27439          //operation which performs CSS transition and keyframe
27440          //animations sniffing. This is always included for each
27441          //element animation procedure if the browser supports
27442          //transitions and/or keyframe animations. The default
27443          //animation is added to the top of the list to prevent
27444          //any previous animations from affecting the element styling
27445          //prior to the element being animated.
27446          if ($sniffer.transitions || $sniffer.animations) {
27447            matches.push($injector.get(selectors['']));
27448          }
27449
27450          for(var i=0; i < classes.length; i++) {
27451            var klass = classes[i],
27452                selectorFactoryName = selectors[klass];
27453            if(selectorFactoryName && !flagMap[klass]) {
27454              matches.push($injector.get(selectorFactoryName));
27455              flagMap[klass] = true;
27456            }
27457          }
27458          return matches;
27459        }
27460      }
27461
27462      function animationRunner(element, animationEvent, className) {
27463        //transcluded directives may sometimes fire an animation using only comment nodes
27464        //best to catch this early on to prevent any animation operations from occurring
27465        var node = element[0];
27466        if(!node) {
27467          return;
27468        }
27469
27470        var isSetClassOperation = animationEvent == 'setClass';
27471        var isClassBased = isSetClassOperation ||
27472                           animationEvent == 'addClass' ||
27473                           animationEvent == 'removeClass';
27474
27475        var classNameAdd, classNameRemove;
27476        if(angular.isArray(className)) {
27477          classNameAdd = className[0];
27478          classNameRemove = className[1];
27479          className = classNameAdd + ' ' + classNameRemove;
27480        }
27481
27482        var currentClassName = element.attr('class');
27483        var classes = currentClassName + ' ' + className;
27484        if(!isAnimatableClassName(classes)) {
27485          return;
27486        }
27487
27488        var beforeComplete = noop,
27489            beforeCancel = [],
27490            before = [],
27491            afterComplete = noop,
27492            afterCancel = [],
27493            after = [];
27494
27495        var animationLookup = (' ' + classes).replace(/\s+/g,'.');
27496        forEach(lookup(animationLookup), function(animationFactory) {
27497          var created = registerAnimation(animationFactory, animationEvent);
27498          if(!created && isSetClassOperation) {
27499            registerAnimation(animationFactory, 'addClass');
27500            registerAnimation(animationFactory, 'removeClass');
27501          }
27502        });
27503
27504        function registerAnimation(animationFactory, event) {
27505          var afterFn = animationFactory[event];
27506          var beforeFn = animationFactory['before' + event.charAt(0).toUpperCase() + event.substr(1)];
27507          if(afterFn || beforeFn) {
27508            if(event == 'leave') {
27509              beforeFn = afterFn;
27510              //when set as null then animation knows to skip this phase
27511              afterFn = null;
27512            }
27513            after.push({
27514              event : event, fn : afterFn
27515            });
27516            before.push({
27517              event : event, fn : beforeFn
27518            });
27519            return true;
27520          }
27521        }
27522
27523        function run(fns, cancellations, allCompleteFn) {
27524          var animations = [];
27525          forEach(fns, function(animation) {
27526            animation.fn && animations.push(animation);
27527          });
27528
27529          var count = 0;
27530          function afterAnimationComplete(index) {
27531            if(cancellations) {
27532              (cancellations[index] || noop)();
27533              if(++count < animations.length) return;
27534              cancellations = null;
27535            }
27536            allCompleteFn();
27537          }
27538
27539          //The code below adds directly to the array in order to work with
27540          //both sync and async animations. Sync animations are when the done()
27541          //operation is called right away. DO NOT REFACTOR!
27542          forEach(animations, function(animation, index) {
27543            var progress = function() {
27544              afterAnimationComplete(index);
27545            };
27546            switch(animation.event) {
27547              case 'setClass':
27548                cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress));
27549                break;
27550              case 'addClass':
27551                cancellations.push(animation.fn(element, classNameAdd || className,     progress));
27552                break;
27553              case 'removeClass':
27554                cancellations.push(animation.fn(element, classNameRemove || className,  progress));
27555                break;
27556              default:
27557                cancellations.push(animation.fn(element, progress));
27558                break;
27559            }
27560          });
27561
27562          if(cancellations && cancellations.length === 0) {
27563            allCompleteFn();
27564          }
27565        }
27566
27567        return {
27568          node : node,
27569          event : animationEvent,
27570          className : className,
27571          isClassBased : isClassBased,
27572          isSetClassOperation : isSetClassOperation,
27573          before : function(allCompleteFn) {
27574            beforeComplete = allCompleteFn;
27575            run(before, beforeCancel, function() {
27576              beforeComplete = noop;
27577              allCompleteFn();
27578            });
27579          },
27580          after : function(allCompleteFn) {
27581            afterComplete = allCompleteFn;
27582            run(after, afterCancel, function() {
27583              afterComplete = noop;
27584              allCompleteFn();
27585            });
27586          },
27587          cancel : function() {
27588            if(beforeCancel) {
27589              forEach(beforeCancel, function(cancelFn) {
27590                (cancelFn || noop)(true);
27591              });
27592              beforeComplete(true);
27593            }
27594            if(afterCancel) {
27595              forEach(afterCancel, function(cancelFn) {
27596                (cancelFn || noop)(true);
27597              });
27598              afterComplete(true);
27599            }
27600          }
27601        };
27602      }
27603
27604      /**
27605       * @ngdoc service
27606       * @name $animate
27607       * @kind function
27608       *
27609       * @description
27610       * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
27611       * When any of these operations are run, the $animate service
27612       * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object)
27613       * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run.
27614       *
27615       * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives
27616       * will work out of the box without any extra configuration.
27617       *
27618       * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
27619       *
27620       * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
27621       *
27622       */
27623      return {
27624        /**
27625         * @ngdoc method
27626         * @name $animate#enter
27627         * @kind function
27628         *
27629         * @description
27630         * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once
27631         * the animation is started, the following CSS classes will be present on the element for the duration of the animation:
27632         *
27633         * Below is a breakdown of each step that occurs during enter animation:
27634         *
27635         * | Animation Step                                                                               | What the element class attribute looks like |
27636         * |----------------------------------------------------------------------------------------------|---------------------------------------------|
27637         * | 1. $animate.enter(...) is called                                                             | class="my-animation"                        |
27638         * | 2. element is inserted into the parentElement element or beside the afterElement element     | class="my-animation"                        |
27639         * | 3. $animate runs any JavaScript-defined animations on the element                            | class="my-animation ng-animate"             |
27640         * | 4. the .ng-enter class is added to the element                                               | class="my-animation ng-animate ng-enter"    |
27641         * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay  | class="my-animation ng-animate ng-enter"    |
27642         * | 6. $animate waits for 10ms (this performs a reflow)                                          | class="my-animation ng-animate ng-enter"    |
27643         * | 7. the .ng-enter-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
27644         * | 8. $animate waits for X milliseconds for the animation to complete                           | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
27645         * | 9. The animation ends and all generated CSS classes are removed from the element             | class="my-animation"                        |
27646         * | 10. The doneCallback() callback is fired (if provided)                                       | class="my-animation"                        |
27647         *
27648         * @param {DOMElement} element the element that will be the focus of the enter animation
27649         * @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation
27650         * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation
27651         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
27652        */
27653        enter : function(element, parentElement, afterElement, doneCallback) {
27654          element = angular.element(element);
27655          parentElement = prepareElement(parentElement);
27656          afterElement = prepareElement(afterElement);
27657
27658          blockElementAnimations(element);
27659          $delegate.enter(element, parentElement, afterElement);
27660          $rootScope.$$postDigest(function() {
27661            element = stripCommentsFromElement(element);
27662            performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback);
27663          });
27664        },
27665
27666        /**
27667         * @ngdoc method
27668         * @name $animate#leave
27669         * @kind function
27670         *
27671         * @description
27672         * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once
27673         * the animation is started, the following CSS classes will be added for the duration of the animation:
27674         *
27675         * Below is a breakdown of each step that occurs during leave animation:
27676         *
27677         * | Animation Step                                                                               | What the element class attribute looks like |
27678         * |----------------------------------------------------------------------------------------------|---------------------------------------------|
27679         * | 1. $animate.leave(...) is called                                                             | class="my-animation"                        |
27680         * | 2. $animate runs any JavaScript-defined animations on the element                            | class="my-animation ng-animate"             |
27681         * | 3. the .ng-leave class is added to the element                                               | class="my-animation ng-animate ng-leave"    |
27682         * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay  | class="my-animation ng-animate ng-leave"    |
27683         * | 5. $animate waits for 10ms (this performs a reflow)                                          | class="my-animation ng-animate ng-leave"    |
27684         * | 6. the .ng-leave-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
27685         * | 7. $animate waits for X milliseconds for the animation to complete                           | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
27686         * | 8. The animation ends and all generated CSS classes are removed from the element             | class="my-animation"                        |
27687         * | 9. The element is removed from the DOM                                                       | ...                                         |
27688         * | 10. The doneCallback() callback is fired (if provided)                                       | ...                                         |
27689         *
27690         * @param {DOMElement} element the element that will be the focus of the leave animation
27691         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
27692        */
27693        leave : function(element, doneCallback) {
27694          element = angular.element(element);
27695          cancelChildAnimations(element);
27696          blockElementAnimations(element);
27697          $rootScope.$$postDigest(function() {
27698            performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
27699              $delegate.leave(element);
27700            }, doneCallback);
27701          });
27702        },
27703
27704        /**
27705         * @ngdoc method
27706         * @name $animate#move
27707         * @kind function
27708         *
27709         * @description
27710         * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or
27711         * add the element directly after the afterElement element if present. Then the move animation will be run. Once
27712         * the animation is started, the following CSS classes will be added for the duration of the animation:
27713         *
27714         * Below is a breakdown of each step that occurs during move animation:
27715         *
27716         * | Animation Step                                                                               | What the element class attribute looks like |
27717         * |----------------------------------------------------------------------------------------------|---------------------------------------------|
27718         * | 1. $animate.move(...) is called                                                              | class="my-animation"                        |
27719         * | 2. element is moved into the parentElement element or beside the afterElement element        | class="my-animation"                        |
27720         * | 3. $animate runs any JavaScript-defined animations on the element                            | class="my-animation ng-animate"             |
27721         * | 4. the .ng-move class is added to the element                                                | class="my-animation ng-animate ng-move"     |
27722         * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay  | class="my-animation ng-animate ng-move"     |
27723         * | 6. $animate waits for 10ms (this performs a reflow)                                          | class="my-animation ng-animate ng-move"     |
27724         * | 7. the .ng-move-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
27725         * | 8. $animate waits for X milliseconds for the animation to complete                           | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
27726         * | 9. The animation ends and all generated CSS classes are removed from the element             | class="my-animation"                        |
27727         * | 10. The doneCallback() callback is fired (if provided)                                       | class="my-animation"                        |
27728         *
27729         * @param {DOMElement} element the element that will be the focus of the move animation
27730         * @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation
27731         * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation
27732         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
27733        */
27734        move : function(element, parentElement, afterElement, doneCallback) {
27735          element = angular.element(element);
27736          parentElement = prepareElement(parentElement);
27737          afterElement = prepareElement(afterElement);
27738
27739          cancelChildAnimations(element);
27740          blockElementAnimations(element);
27741          $delegate.move(element, parentElement, afterElement);
27742          $rootScope.$$postDigest(function() {
27743            element = stripCommentsFromElement(element);
27744            performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback);
27745          });
27746        },
27747
27748        /**
27749         * @ngdoc method
27750         * @name $animate#addClass
27751         *
27752         * @description
27753         * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
27754         * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
27755         * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
27756         * or keyframes are defined on the -add or base CSS class).
27757         *
27758         * Below is a breakdown of each step that occurs during addClass animation:
27759         *
27760         * | Animation Step                                                                                 | What the element class attribute looks like |
27761         * |------------------------------------------------------------------------------------------------|---------------------------------------------|
27762         * | 1. $animate.addClass(element, 'super') is called                                               | class="my-animation"                        |
27763         * | 2. $animate runs any JavaScript-defined animations on the element                              | class="my-animation ng-animate"             |
27764         * | 3. the .super-add class are added to the element                                               | class="my-animation ng-animate super-add"   |
27765         * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay    | class="my-animation ng-animate super-add"   |
27766         * | 5. $animate waits for 10ms (this performs a reflow)                                            | class="my-animation ng-animate super-add"   |
27767         * | 6. the .super, .super-add-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super super-add super-add-active"          |
27768         * | 7. $animate waits for X milliseconds for the animation to complete                             | class="my-animation super super-add super-add-active"  |
27769         * | 8. The animation ends and all generated CSS classes are removed from the element               | class="my-animation super"                  |
27770         * | 9. The super class is kept on the element                                                      | class="my-animation super"                  |
27771         * | 10. The doneCallback() callback is fired (if provided)                                         | class="my-animation super"                  |
27772         *
27773         * @param {DOMElement} element the element that will be animated
27774         * @param {string} className the CSS class that will be added to the element and then animated
27775         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
27776        */
27777        addClass : function(element, className, doneCallback) {
27778          element = angular.element(element);
27779          element = stripCommentsFromElement(element);
27780          performAnimation('addClass', className, element, null, null, function() {
27781            $delegate.addClass(element, className);
27782          }, doneCallback);
27783        },
27784
27785        /**
27786         * @ngdoc method
27787         * @name $animate#removeClass
27788         *
27789         * @description
27790         * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value
27791         * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in
27792         * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if
27793         * no CSS transitions or keyframes are defined on the -remove or base CSS classes).
27794         *
27795         * Below is a breakdown of each step that occurs during removeClass animation:
27796         *
27797         * | Animation Step                                                                                | What the element class attribute looks like     |
27798         * |-----------------------------------------------------------------------------------------------|---------------------------------------------|
27799         * | 1. $animate.removeClass(element, 'super') is called                                           | class="my-animation super"                  |
27800         * | 2. $animate runs any JavaScript-defined animations on the element                             | class="my-animation super ng-animate"       |
27801         * | 3. the .super-remove class are added to the element                                           | class="my-animation super ng-animate super-remove"|
27802         * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay   | class="my-animation super ng-animate super-remove"   |
27803         * | 5. $animate waits for 10ms (this performs a reflow)                                           | class="my-animation super ng-animate super-remove"   |
27804         * | 6. the .super-remove-active and .ng-animate-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super-remove super-remove-active"          |
27805         * | 7. $animate waits for X milliseconds for the animation to complete                            | class="my-animation ng-animate ng-animate-active super-remove super-remove-active"   |
27806         * | 8. The animation ends and all generated CSS classes are removed from the element              | class="my-animation"                        |
27807         * | 9. The doneCallback() callback is fired (if provided)                                         | class="my-animation"                        |
27808         *
27809         *
27810         * @param {DOMElement} element the element that will be animated
27811         * @param {string} className the CSS class that will be animated and then removed from the element
27812         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
27813        */
27814        removeClass : function(element, className, doneCallback) {
27815          element = angular.element(element);
27816          element = stripCommentsFromElement(element);
27817          performAnimation('removeClass', className, element, null, null, function() {
27818            $delegate.removeClass(element, className);
27819          }, doneCallback);
27820        },
27821
27822          /**
27823           *
27824           * @ngdoc function
27825           * @name $animate#setClass
27826           * @function
27827           * @description Adds and/or removes the given CSS classes to and from the element.
27828           * Once complete, the done() callback will be fired (if provided).
27829           * @param {DOMElement} element the element which will its CSS classes changed
27830           *   removed from it
27831           * @param {string} add the CSS classes which will be added to the element
27832           * @param {string} remove the CSS class which will be removed from the element
27833           * @param {Function=} done the callback function (if provided) that will be fired after the
27834           *   CSS classes have been set on the element
27835           */
27836        setClass : function(element, add, remove, doneCallback) {
27837          element = angular.element(element);
27838          element = stripCommentsFromElement(element);
27839          performAnimation('setClass', [add, remove], element, null, null, function() {
27840            $delegate.setClass(element, add, remove);
27841          }, doneCallback);
27842        },
27843
27844        /**
27845         * @ngdoc method
27846         * @name $animate#enabled
27847         * @kind function
27848         *
27849         * @param {boolean=} value If provided then set the animation on or off.
27850         * @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation
27851         * @return {boolean} Current animation state.
27852         *
27853         * @description
27854         * Globally enables/disables animations.
27855         *
27856        */
27857        enabled : function(value, element) {
27858          switch(arguments.length) {
27859            case 2:
27860              if(value) {
27861                cleanup(element);
27862              } else {
27863                var data = element.data(NG_ANIMATE_STATE) || {};
27864                data.disabled = true;
27865                element.data(NG_ANIMATE_STATE, data);
27866              }
27867            break;
27868
27869            case 1:
27870              rootAnimateState.disabled = !value;
27871            break;
27872
27873            default:
27874              value = !rootAnimateState.disabled;
27875            break;
27876          }
27877          return !!value;
27878         }
27879      };
27880
27881      /*
27882        all animations call this shared animation triggering function internally.
27883        The animationEvent variable refers to the JavaScript animation event that will be triggered
27884        and the className value is the name of the animation that will be applied within the
27885        CSS code. Element, parentElement and afterElement are provided DOM elements for the animation
27886        and the onComplete callback will be fired once the animation is fully complete.
27887      */
27888      function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
27889
27890        var runner = animationRunner(element, animationEvent, className);
27891        if(!runner) {
27892          fireDOMOperation();
27893          fireBeforeCallbackAsync();
27894          fireAfterCallbackAsync();
27895          closeAnimation();
27896          return;
27897        }
27898
27899        className = runner.className;
27900        var elementEvents = angular.element._data(runner.node);
27901        elementEvents = elementEvents && elementEvents.events;
27902
27903        if (!parentElement) {
27904          parentElement = afterElement ? afterElement.parent() : element.parent();
27905        }
27906
27907        var ngAnimateState  = element.data(NG_ANIMATE_STATE) || {};
27908        var runningAnimations     = ngAnimateState.active || {};
27909        var totalActiveAnimations = ngAnimateState.totalActive || 0;
27910        var lastAnimation         = ngAnimateState.last;
27911
27912        //only allow animations if the currently running animation is not structural
27913        //or if there is no animation running at all
27914        var skipAnimations;
27915        if (runner.isClassBased) {
27916          skipAnimations = ngAnimateState.running ||
27917                           ngAnimateState.disabled ||
27918                           (lastAnimation && !lastAnimation.isClassBased);
27919        }
27920
27921        //skip the animation if animations are disabled, a parent is already being animated,
27922        //the element is not currently attached to the document body or then completely close
27923        //the animation if any matching animations are not found at all.
27924        //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found.
27925        if (skipAnimations || animationsDisabled(element, parentElement)) {
27926          fireDOMOperation();
27927          fireBeforeCallbackAsync();
27928          fireAfterCallbackAsync();
27929          closeAnimation();
27930          return;
27931        }
27932
27933        var skipAnimation = false;
27934        if(totalActiveAnimations > 0) {
27935          var animationsToCancel = [];
27936          if(!runner.isClassBased) {
27937            if(animationEvent == 'leave' && runningAnimations['ng-leave']) {
27938              skipAnimation = true;
27939            } else {
27940              //cancel all animations when a structural animation takes place
27941              for(var klass in runningAnimations) {
27942                animationsToCancel.push(runningAnimations[klass]);
27943                cleanup(element, klass);
27944              }
27945              runningAnimations = {};
27946              totalActiveAnimations = 0;
27947            }
27948          } else if(lastAnimation.event == 'setClass') {
27949            animationsToCancel.push(lastAnimation);
27950            cleanup(element, className);
27951          }
27952          else if(runningAnimations[className]) {
27953            var current = runningAnimations[className];
27954            if(current.event == animationEvent) {
27955              skipAnimation = true;
27956            } else {
27957              animationsToCancel.push(current);
27958              cleanup(element, className);
27959            }
27960          }
27961
27962          if(animationsToCancel.length > 0) {
27963            forEach(animationsToCancel, function(operation) {
27964              operation.cancel();
27965            });
27966          }
27967        }
27968
27969        if(runner.isClassBased && !runner.isSetClassOperation && !skipAnimation) {
27970          skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR
27971        }
27972
27973        if(skipAnimation) {
27974          fireDOMOperation();
27975          fireBeforeCallbackAsync();
27976          fireAfterCallbackAsync();
27977          fireDoneCallbackAsync();
27978          return;
27979        }
27980
27981        if(animationEvent == 'leave') {
27982          //there's no need to ever remove the listener since the element
27983          //will be removed (destroyed) after the leave animation ends or
27984          //is cancelled midway
27985          element.one('$destroy', function(e) {
27986            var element = angular.element(this);
27987            var state = element.data(NG_ANIMATE_STATE);
27988            if(state) {
27989              var activeLeaveAnimation = state.active['ng-leave'];
27990              if(activeLeaveAnimation) {
27991                activeLeaveAnimation.cancel();
27992                cleanup(element, 'ng-leave');
27993              }
27994            }
27995          });
27996        }
27997
27998        //the ng-animate class does nothing, but it's here to allow for
27999        //parent animations to find and cancel child animations when needed
28000        element.addClass(NG_ANIMATE_CLASS_NAME);
28001
28002        var localAnimationCount = globalAnimationCounter++;
28003        totalActiveAnimations++;
28004        runningAnimations[className] = runner;
28005
28006        element.data(NG_ANIMATE_STATE, {
28007          last : runner,
28008          active : runningAnimations,
28009          index : localAnimationCount,
28010          totalActive : totalActiveAnimations
28011        });
28012
28013        //first we run the before animations and when all of those are complete
28014        //then we perform the DOM operation and run the next set of animations
28015        fireBeforeCallbackAsync();
28016        runner.before(function(cancelled) {
28017          var data = element.data(NG_ANIMATE_STATE);
28018          cancelled = cancelled ||
28019                        !data || !data.active[className] ||
28020                        (runner.isClassBased && data.active[className].event != animationEvent);
28021
28022          fireDOMOperation();
28023          if(cancelled === true) {
28024            closeAnimation();
28025          } else {
28026            fireAfterCallbackAsync();
28027            runner.after(closeAnimation);
28028          }
28029        });
28030
28031        function fireDOMCallback(animationPhase) {
28032          var eventName = '$animate:' + animationPhase;
28033          if(elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) {
28034            $$asyncCallback(function() {
28035              element.triggerHandler(eventName, {
28036                event : animationEvent,
28037                className : className
28038              });
28039            });
28040          }
28041        }
28042
28043        function fireBeforeCallbackAsync() {
28044          fireDOMCallback('before');
28045        }
28046
28047        function fireAfterCallbackAsync() {
28048          fireDOMCallback('after');
28049        }
28050
28051        function fireDoneCallbackAsync() {
28052          fireDOMCallback('close');
28053          if(doneCallback) {
28054            $$asyncCallback(function() {
28055              doneCallback();
28056            });
28057          }
28058        }
28059
28060        //it is less complicated to use a flag than managing and canceling
28061        //timeouts containing multiple callbacks.
28062        function fireDOMOperation() {
28063          if(!fireDOMOperation.hasBeenRun) {
28064            fireDOMOperation.hasBeenRun = true;
28065            domOperation();
28066          }
28067        }
28068
28069        function closeAnimation() {
28070          if(!closeAnimation.hasBeenRun) {
28071            closeAnimation.hasBeenRun = true;
28072            var data = element.data(NG_ANIMATE_STATE);
28073            if(data) {
28074              /* only structural animations wait for reflow before removing an
28075                 animation, but class-based animations don't. An example of this
28076                 failing would be when a parent HTML tag has a ng-class attribute
28077                 causing ALL directives below to skip animations during the digest */
28078              if(runner && runner.isClassBased) {
28079                cleanup(element, className);
28080              } else {
28081                $$asyncCallback(function() {
28082                  var data = element.data(NG_ANIMATE_STATE) || {};
28083                  if(localAnimationCount == data.index) {
28084                    cleanup(element, className, animationEvent);
28085                  }
28086                });
28087                element.data(NG_ANIMATE_STATE, data);
28088              }
28089            }
28090            fireDoneCallbackAsync();
28091          }
28092        }
28093      }
28094
28095      function cancelChildAnimations(element) {
28096        var node = extractElementNode(element);
28097        if (node) {
28098          var nodes = angular.isFunction(node.getElementsByClassName) ?
28099            node.getElementsByClassName(NG_ANIMATE_CLASS_NAME) :
28100            node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME);
28101          forEach(nodes, function(element) {
28102            element = angular.element(element);
28103            var data = element.data(NG_ANIMATE_STATE);
28104            if(data && data.active) {
28105              forEach(data.active, function(runner) {
28106                runner.cancel();
28107              });
28108            }
28109          });
28110        }
28111      }
28112
28113      function cleanup(element, className) {
28114        if(isMatchingElement(element, $rootElement)) {
28115          if(!rootAnimateState.disabled) {
28116            rootAnimateState.running = false;
28117            rootAnimateState.structural = false;
28118          }
28119        } else if(className) {
28120          var data = element.data(NG_ANIMATE_STATE) || {};
28121
28122          var removeAnimations = className === true;
28123          if(!removeAnimations && data.active && data.active[className]) {
28124            data.totalActive--;
28125            delete data.active[className];
28126          }
28127
28128          if(removeAnimations || !data.totalActive) {
28129            element.removeClass(NG_ANIMATE_CLASS_NAME);
28130            element.removeData(NG_ANIMATE_STATE);
28131          }
28132        }
28133      }
28134
28135      function animationsDisabled(element, parentElement) {
28136        if (rootAnimateState.disabled) {
28137          return true;
28138        }
28139
28140        if (isMatchingElement(element, $rootElement)) {
28141          return rootAnimateState.running;
28142        }
28143
28144        var allowChildAnimations, parentRunningAnimation, hasParent;
28145        do {
28146          //the element did not reach the root element which means that it
28147          //is not apart of the DOM. Therefore there is no reason to do
28148          //any animations on it
28149          if (parentElement.length === 0) break;
28150
28151          var isRoot = isMatchingElement(parentElement, $rootElement);
28152          var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {});
28153          if (state.disabled) {
28154            return true;
28155          }
28156
28157          //no matter what, for an animation to work it must reach the root element
28158          //this implies that the element is attached to the DOM when the animation is run
28159          if (isRoot) {
28160            hasParent = true;
28161          }
28162
28163          //once a flag is found that is strictly false then everything before
28164          //it will be discarded and all child animations will be restricted
28165          if (allowChildAnimations !== false) {
28166            var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN);
28167            if(angular.isDefined(animateChildrenFlag)) {
28168              allowChildAnimations = animateChildrenFlag;
28169            }
28170          }
28171
28172          parentRunningAnimation = parentRunningAnimation ||
28173                                   state.running ||
28174                                   (state.last && !state.last.isClassBased);
28175        }
28176        while(parentElement = parentElement.parent());
28177
28178        return !hasParent || (!allowChildAnimations && parentRunningAnimation);
28179      }
28180    }]);
28181
28182    $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow',
28183                           function($window,   $sniffer,   $timeout,   $$animateReflow) {
28184      // Detect proper transitionend/animationend event names.
28185      var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
28186
28187      // If unprefixed events are not supported but webkit-prefixed are, use the latter.
28188      // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
28189      // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
28190      // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
28191      // Register both events in case `window.onanimationend` is not supported because of that,
28192      // do the same for `transitionend` as Safari is likely to exhibit similar behavior.
28193      // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
28194      // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition
28195      if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
28196        CSS_PREFIX = '-webkit-';
28197        TRANSITION_PROP = 'WebkitTransition';
28198        TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
28199      } else {
28200        TRANSITION_PROP = 'transition';
28201        TRANSITIONEND_EVENT = 'transitionend';
28202      }
28203
28204      if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
28205        CSS_PREFIX = '-webkit-';
28206        ANIMATION_PROP = 'WebkitAnimation';
28207        ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
28208      } else {
28209        ANIMATION_PROP = 'animation';
28210        ANIMATIONEND_EVENT = 'animationend';
28211      }
28212
28213      var DURATION_KEY = 'Duration';
28214      var PROPERTY_KEY = 'Property';
28215      var DELAY_KEY = 'Delay';
28216      var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
28217      var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
28218      var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
28219      var NG_ANIMATE_BLOCK_CLASS_NAME = 'ng-animate-block-transitions';
28220      var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
28221      var CLOSING_TIME_BUFFER = 1.5;
28222      var ONE_SECOND = 1000;
28223
28224      var lookupCache = {};
28225      var parentCounter = 0;
28226      var animationReflowQueue = [];
28227      var cancelAnimationReflow;
28228      function afterReflow(element, callback) {
28229        if(cancelAnimationReflow) {
28230          cancelAnimationReflow();
28231        }
28232        animationReflowQueue.push(callback);
28233        cancelAnimationReflow = $$animateReflow(function() {
28234          forEach(animationReflowQueue, function(fn) {
28235            fn();
28236          });
28237
28238          animationReflowQueue = [];
28239          cancelAnimationReflow = null;
28240          lookupCache = {};
28241        });
28242      }
28243
28244      var closingTimer = null;
28245      var closingTimestamp = 0;
28246      var animationElementQueue = [];
28247      function animationCloseHandler(element, totalTime) {
28248        var node = extractElementNode(element);
28249        element = angular.element(node);
28250
28251        //this item will be garbage collected by the closing
28252        //animation timeout
28253        animationElementQueue.push(element);
28254
28255        //but it may not need to cancel out the existing timeout
28256        //if the timestamp is less than the previous one
28257        var futureTimestamp = Date.now() + totalTime;
28258        if(futureTimestamp <= closingTimestamp) {
28259          return;
28260        }
28261
28262        $timeout.cancel(closingTimer);
28263
28264        closingTimestamp = futureTimestamp;
28265        closingTimer = $timeout(function() {
28266          closeAllAnimations(animationElementQueue);
28267          animationElementQueue = [];
28268        }, totalTime, false);
28269      }
28270
28271      function closeAllAnimations(elements) {
28272        forEach(elements, function(element) {
28273          var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
28274          if(elementData) {
28275            (elementData.closeAnimationFn || noop)();
28276          }
28277        });
28278      }
28279
28280      function getElementAnimationDetails(element, cacheKey) {
28281        var data = cacheKey ? lookupCache[cacheKey] : null;
28282        if(!data) {
28283          var transitionDuration = 0;
28284          var transitionDelay = 0;
28285          var animationDuration = 0;
28286          var animationDelay = 0;
28287          var transitionDelayStyle;
28288          var animationDelayStyle;
28289          var transitionDurationStyle;
28290          var transitionPropertyStyle;
28291
28292          //we want all the styles defined before and after
28293          forEach(element, function(element) {
28294            if (element.nodeType == ELEMENT_NODE) {
28295              var elementStyles = $window.getComputedStyle(element) || {};
28296
28297              transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY];
28298
28299              transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration);
28300
28301              transitionPropertyStyle = elementStyles[TRANSITION_PROP + PROPERTY_KEY];
28302
28303              transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY];
28304
28305              transitionDelay  = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay);
28306
28307              animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY];
28308
28309              animationDelay   = Math.max(parseMaxTime(animationDelayStyle), animationDelay);
28310
28311              var aDuration  = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]);
28312
28313              if(aDuration > 0) {
28314                aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1;
28315              }
28316
28317              animationDuration = Math.max(aDuration, animationDuration);
28318            }
28319          });
28320          data = {
28321            total : 0,
28322            transitionPropertyStyle: transitionPropertyStyle,
28323            transitionDurationStyle: transitionDurationStyle,
28324            transitionDelayStyle: transitionDelayStyle,
28325            transitionDelay: transitionDelay,
28326            transitionDuration: transitionDuration,
28327            animationDelayStyle: animationDelayStyle,
28328            animationDelay: animationDelay,
28329            animationDuration: animationDuration
28330          };
28331          if(cacheKey) {
28332            lookupCache[cacheKey] = data;
28333          }
28334        }
28335        return data;
28336      }
28337
28338      function parseMaxTime(str) {
28339        var maxValue = 0;
28340        var values = angular.isString(str) ?
28341          str.split(/\s*,\s*/) :
28342          [];
28343        forEach(values, function(value) {
28344          maxValue = Math.max(parseFloat(value) || 0, maxValue);
28345        });
28346        return maxValue;
28347      }
28348
28349      function getCacheKey(element) {
28350        var parentElement = element.parent();
28351        var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY);
28352        if(!parentID) {
28353          parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
28354          parentID = parentCounter;
28355        }
28356        return parentID + '-' + extractElementNode(element).getAttribute('class');
28357      }
28358
28359      function animateSetup(animationEvent, element, className, calculationDecorator) {
28360        var cacheKey = getCacheKey(element);
28361        var eventCacheKey = cacheKey + ' ' + className;
28362        var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
28363
28364        var stagger = {};
28365        if(itemIndex > 0) {
28366          var staggerClassName = className + '-stagger';
28367          var staggerCacheKey = cacheKey + ' ' + staggerClassName;
28368          var applyClasses = !lookupCache[staggerCacheKey];
28369
28370          applyClasses && element.addClass(staggerClassName);
28371
28372          stagger = getElementAnimationDetails(element, staggerCacheKey);
28373
28374          applyClasses && element.removeClass(staggerClassName);
28375        }
28376
28377        /* the animation itself may need to add/remove special CSS classes
28378         * before calculating the anmation styles */
28379        calculationDecorator = calculationDecorator ||
28380                               function(fn) { return fn(); };
28381
28382        element.addClass(className);
28383
28384        var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {};
28385
28386        var timings = calculationDecorator(function() {
28387          return getElementAnimationDetails(element, eventCacheKey);
28388        });
28389
28390        var transitionDuration = timings.transitionDuration;
28391        var animationDuration = timings.animationDuration;
28392        if(transitionDuration === 0 && animationDuration === 0) {
28393          element.removeClass(className);
28394          return false;
28395        }
28396
28397        element.data(NG_ANIMATE_CSS_DATA_KEY, {
28398          running : formerData.running || 0,
28399          itemIndex : itemIndex,
28400          stagger : stagger,
28401          timings : timings,
28402          closeAnimationFn : noop
28403        });
28404
28405        //temporarily disable the transition so that the enter styles
28406        //don't animate twice (this is here to avoid a bug in Chrome/FF).
28407        var isCurrentlyAnimating = formerData.running > 0 || animationEvent == 'setClass';
28408        if(transitionDuration > 0) {
28409          blockTransitions(element, className, isCurrentlyAnimating);
28410        }
28411
28412        //staggering keyframe animations work by adjusting the `animation-delay` CSS property
28413        //on the given element, however, the delay value can only calculated after the reflow
28414        //since by that time $animate knows how many elements are being animated. Therefore,
28415        //until the reflow occurs the element needs to be blocked (where the keyframe animation
28416        //is set to `none 0s`). This blocking mechanism should only be set for when a stagger
28417        //animation is detected and when the element item index is greater than 0.
28418        if(animationDuration > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0) {
28419          blockKeyframeAnimations(element);
28420        }
28421
28422        return true;
28423      }
28424
28425      function isStructuralAnimation(className) {
28426        return className == 'ng-enter' || className == 'ng-move' || className == 'ng-leave';
28427      }
28428
28429      function blockTransitions(element, className, isAnimating) {
28430        if(isStructuralAnimation(className) || !isAnimating) {
28431          extractElementNode(element).style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
28432        } else {
28433          element.addClass(NG_ANIMATE_BLOCK_CLASS_NAME);
28434        }
28435      }
28436
28437      function blockKeyframeAnimations(element) {
28438        extractElementNode(element).style[ANIMATION_PROP] = 'none 0s';
28439      }
28440
28441      function unblockTransitions(element, className) {
28442        var prop = TRANSITION_PROP + PROPERTY_KEY;
28443        var node = extractElementNode(element);
28444        if(node.style[prop] && node.style[prop].length > 0) {
28445          node.style[prop] = '';
28446        }
28447        element.removeClass(NG_ANIMATE_BLOCK_CLASS_NAME);
28448      }
28449
28450      function unblockKeyframeAnimations(element) {
28451        var prop = ANIMATION_PROP;
28452        var node = extractElementNode(element);
28453        if(node.style[prop] && node.style[prop].length > 0) {
28454          node.style[prop] = '';
28455        }
28456      }
28457
28458      function animateRun(animationEvent, element, className, activeAnimationComplete) {
28459        var node = extractElementNode(element);
28460        var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
28461        if(node.getAttribute('class').indexOf(className) == -1 || !elementData) {
28462          activeAnimationComplete();
28463          return;
28464        }
28465
28466        var activeClassName = '';
28467        forEach(className.split(' '), function(klass, i) {
28468          activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
28469        });
28470
28471        var stagger = elementData.stagger;
28472        var timings = elementData.timings;
28473        var itemIndex = elementData.itemIndex;
28474        var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
28475        var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
28476        var maxDelayTime = maxDelay * ONE_SECOND;
28477
28478        var startTime = Date.now();
28479        var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
28480
28481        var style = '', appliedStyles = [];
28482        if(timings.transitionDuration > 0) {
28483          var propertyStyle = timings.transitionPropertyStyle;
28484          if(propertyStyle.indexOf('all') == -1) {
28485            style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ';';
28486            style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ';';
28487            appliedStyles.push(CSS_PREFIX + 'transition-property');
28488            appliedStyles.push(CSS_PREFIX + 'transition-duration');
28489          }
28490        }
28491
28492        if(itemIndex > 0) {
28493          if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
28494            var delayStyle = timings.transitionDelayStyle;
28495            style += CSS_PREFIX + 'transition-delay: ' +
28496                     prepareStaggerDelay(delayStyle, stagger.transitionDelay, itemIndex) + '; ';
28497            appliedStyles.push(CSS_PREFIX + 'transition-delay');
28498          }
28499
28500          if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
28501            style += CSS_PREFIX + 'animation-delay: ' +
28502                     prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, itemIndex) + '; ';
28503            appliedStyles.push(CSS_PREFIX + 'animation-delay');
28504          }
28505        }
28506
28507        if(appliedStyles.length > 0) {
28508          //the element being animated may sometimes contain comment nodes in
28509          //the jqLite object, so we're safe to use a single variable to house
28510          //the styles since there is always only one element being animated
28511          var oldStyle = node.getAttribute('style') || '';
28512          node.setAttribute('style', oldStyle + '; ' + style);
28513        }
28514
28515        element.on(css3AnimationEvents, onAnimationProgress);
28516        element.addClass(activeClassName);
28517        elementData.closeAnimationFn = function() {
28518          onEnd();
28519          activeAnimationComplete();
28520        };
28521
28522        var staggerTime       = itemIndex * (Math.max(stagger.animationDelay, stagger.transitionDelay) || 0);
28523        var animationTime     = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER;
28524        var totalTime         = (staggerTime + animationTime) * ONE_SECOND;
28525
28526        elementData.running++;
28527        animationCloseHandler(element, totalTime);
28528        return onEnd;
28529
28530        // This will automatically be called by $animate so
28531        // there is no need to attach this internally to the
28532        // timeout done method.
28533        function onEnd(cancelled) {
28534          element.off(css3AnimationEvents, onAnimationProgress);
28535          element.removeClass(activeClassName);
28536          animateClose(element, className);
28537          var node = extractElementNode(element);
28538          for (var i in appliedStyles) {
28539            node.style.removeProperty(appliedStyles[i]);
28540          }
28541        }
28542
28543        function onAnimationProgress(event) {
28544          event.stopPropagation();
28545          var ev = event.originalEvent || event;
28546          var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
28547
28548          /* Firefox (or possibly just Gecko) likes to not round values up
28549           * when a ms measurement is used for the animation */
28550          var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
28551
28552          /* $manualTimeStamp is a mocked timeStamp value which is set
28553           * within browserTrigger(). This is only here so that tests can
28554           * mock animations properly. Real events fallback to event.timeStamp,
28555           * or, if they don't, then a timeStamp is automatically created for them.
28556           * We're checking to see if the timeStamp surpasses the expected delay,
28557           * but we're using elapsedTime instead of the timeStamp on the 2nd
28558           * pre-condition since animations sometimes close off early */
28559          if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
28560            activeAnimationComplete();
28561          }
28562        }
28563      }
28564
28565      function prepareStaggerDelay(delayStyle, staggerDelay, index) {
28566        var style = '';
28567        forEach(delayStyle.split(','), function(val, i) {
28568          style += (i > 0 ? ',' : '') +
28569                   (index * staggerDelay + parseInt(val, 10)) + 's';
28570        });
28571        return style;
28572      }
28573
28574      function animateBefore(animationEvent, element, className, calculationDecorator) {
28575        if(animateSetup(animationEvent, element, className, calculationDecorator)) {
28576          return function(cancelled) {
28577            cancelled && animateClose(element, className);
28578          };
28579        }
28580      }
28581
28582      function animateAfter(animationEvent, element, className, afterAnimationComplete) {
28583        if(element.data(NG_ANIMATE_CSS_DATA_KEY)) {
28584          return animateRun(animationEvent, element, className, afterAnimationComplete);
28585        } else {
28586          animateClose(element, className);
28587          afterAnimationComplete();
28588        }
28589      }
28590
28591      function animate(animationEvent, element, className, animationComplete) {
28592        //If the animateSetup function doesn't bother returning a
28593        //cancellation function then it means that there is no animation
28594        //to perform at all
28595        var preReflowCancellation = animateBefore(animationEvent, element, className);
28596        if(!preReflowCancellation) {
28597          animationComplete();
28598          return;
28599        }
28600
28601        //There are two cancellation functions: one is before the first
28602        //reflow animation and the second is during the active state
28603        //animation. The first function will take care of removing the
28604        //data from the element which will not make the 2nd animation
28605        //happen in the first place
28606        var cancel = preReflowCancellation;
28607        afterReflow(element, function() {
28608          unblockTransitions(element, className);
28609          unblockKeyframeAnimations(element);
28610          //once the reflow is complete then we point cancel to
28611          //the new cancellation function which will remove all of the
28612          //animation properties from the active animation
28613          cancel = animateAfter(animationEvent, element, className, animationComplete);
28614        });
28615
28616        return function(cancelled) {
28617          (cancel || noop)(cancelled);
28618        };
28619      }
28620
28621      function animateClose(element, className) {
28622        element.removeClass(className);
28623        var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
28624        if(data) {
28625          if(data.running) {
28626            data.running--;
28627          }
28628          if(!data.running || data.running === 0) {
28629            element.removeData(NG_ANIMATE_CSS_DATA_KEY);
28630          }
28631        }
28632      }
28633
28634      return {
28635        enter : function(element, animationCompleted) {
28636          return animate('enter', element, 'ng-enter', animationCompleted);
28637        },
28638
28639        leave : function(element, animationCompleted) {
28640          return animate('leave', element, 'ng-leave', animationCompleted);
28641        },
28642
28643        move : function(element, animationCompleted) {
28644          return animate('move', element, 'ng-move', animationCompleted);
28645        },
28646
28647        beforeSetClass : function(element, add, remove, animationCompleted) {
28648          var className = suffixClasses(remove, '-remove') + ' ' +
28649                          suffixClasses(add, '-add');
28650          var cancellationMethod = animateBefore('setClass', element, className, function(fn) {
28651            /* when classes are removed from an element then the transition style
28652             * that is applied is the transition defined on the element without the
28653             * CSS class being there. This is how CSS3 functions outside of ngAnimate.
28654             * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
28655            var klass = element.attr('class');
28656            element.removeClass(remove);
28657            element.addClass(add);
28658            var timings = fn();
28659            element.attr('class', klass);
28660            return timings;
28661          });
28662
28663          if(cancellationMethod) {
28664            afterReflow(element, function() {
28665              unblockTransitions(element, className);
28666              unblockKeyframeAnimations(element);
28667              animationCompleted();
28668            });
28669            return cancellationMethod;
28670          }
28671          animationCompleted();
28672        },
28673
28674        beforeAddClass : function(element, className, animationCompleted) {
28675          var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), function(fn) {
28676
28677            /* when a CSS class is added to an element then the transition style that
28678             * is applied is the transition defined on the element when the CSS class
28679             * is added at the time of the animation. This is how CSS3 functions
28680             * outside of ngAnimate. */
28681            element.addClass(className);
28682            var timings = fn();
28683            element.removeClass(className);
28684            return timings;
28685          });
28686
28687          if(cancellationMethod) {
28688            afterReflow(element, function() {
28689              unblockTransitions(element, className);
28690              unblockKeyframeAnimations(element);
28691              animationCompleted();
28692            });
28693            return cancellationMethod;
28694          }
28695          animationCompleted();
28696        },
28697
28698        setClass : function(element, add, remove, animationCompleted) {
28699          remove = suffixClasses(remove, '-remove');
28700          add = suffixClasses(add, '-add');
28701          var className = remove + ' ' + add;
28702          return animateAfter('setClass', element, className, animationCompleted);
28703        },
28704
28705        addClass : function(element, className, animationCompleted) {
28706          return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted);
28707        },
28708
28709        beforeRemoveClass : function(element, className, animationCompleted) {
28710          var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), function(fn) {
28711            /* when classes are removed from an element then the transition style
28712             * that is applied is the transition defined on the element without the
28713             * CSS class being there. This is how CSS3 functions outside of ngAnimate.
28714             * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
28715            var klass = element.attr('class');
28716            element.removeClass(className);
28717            var timings = fn();
28718            element.attr('class', klass);
28719            return timings;
28720          });
28721
28722          if(cancellationMethod) {
28723            afterReflow(element, function() {
28724              unblockTransitions(element, className);
28725              unblockKeyframeAnimations(element);
28726              animationCompleted();
28727            });
28728            return cancellationMethod;
28729          }
28730          animationCompleted();
28731        },
28732
28733        removeClass : function(element, className, animationCompleted) {
28734          return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted);
28735        }
28736      };
28737
28738      function suffixClasses(classes, suffix) {
28739        var className = '';
28740        classes = angular.isArray(classes) ? classes : classes.split(/\s+/);
28741        forEach(classes, function(klass, i) {
28742          if(klass && klass.length > 0) {
28743            className += (i > 0 ? ' ' : '') + klass + suffix;
28744          }
28745        });
28746        return className;
28747      }
28748    }]);
28749  }]);
28750
28751
28752})(window, window.angular);
28753
28754/*!
28755 * fancyBox - jQuery Plugin
28756 * version: 3.0.0 Beta 1 (Tue, 29 Jan 2013)
28757 * @requires jQuery v1.7 or later
28758 *
28759 * Examples at http://fancyapps.com/fancybox/
28760 * License: www.fancyapps.com/fancybox/#license
28761 *
28762 * Copyright 2013 Janis Skarnelis - [email protected]
28763 *
28764 */
28765
28766(function (window, document, $, undefined) {
28767	"use strict";
28768
28769	var W  = $(window),
28770		D  = $(document),
28771		H  = $('html');
28772
28773	var F = $.fancybox = function () {
28774		F.open.apply( this, arguments );
28775	};
28776
28777	var isTouch = F.isTouch = (document.createTouch !== undefined || window.ontouchstart !== undefined);
28778
28779	var isQuery = function(object) {
28780		return object && object.hasOwnProperty && object instanceof $;
28781	};
28782
28783	var isString = function(str) {
28784		return str && $.type(str) === "string";
28785	};
28786
28787	var isPercentage = function(str) {
28788		return isString(str) && str.indexOf('%') > 0;
28789	};
28790
28791	var getScalar = function(orig, dim) {
28792		var value = parseFloat(orig, 10) || 0;
28793
28794		if (dim && isPercentage(orig)) {
28795			value = F.getViewport()[ dim ] / 100 * value;
28796		}
28797
28798		return Math.ceil(value);
28799	};
28800
28801	var getValue = function(value, dim) {
28802		return getScalar(value, dim) + 'px';
28803	};
28804
28805	var getTime = Date.now || function() {
28806		return +new Date;
28807	};
28808
28809	var removeWrap = function(what) {
28810		var el = isString(what) ? $(what) : what;
28811
28812		if (el && el.length) {
28813			el.removeClass('fancybox-wrap').stop(true).trigger('onReset').hide().unbind();
28814
28815			try {
28816				el.find('iframe').unbind().attr('src', isTouch ? '' : '//about:blank');
28817
28818				// Give the document in the iframe to get a chance to unload properly before remove
28819				setTimeout(function () {
28820					el.empty().remove();
28821
28822					// Remove the lock if there are no elements
28823					if (F.lock && !F.coming && !F.current) {
28824						var scrollV, scrollH;
28825
28826						$('.fancybox-margin').removeClass('fancybox-margin');
28827
28828						scrollV = W.scrollTop();
28829						scrollH = W.scrollLeft();
28830
28831						H.removeClass('fancybox-lock');
28832
28833						F.lock.remove();
28834
28835						F.lock = null;
28836
28837						W.scrollTop( scrollV ).scrollLeft( scrollH );
28838					}
28839				}, 150);
28840
28841			} catch(e) {}
28842		}
28843	};
28844
28845	$.extend(F, {
28846		// The current version of fancyBox
28847		version: '3.0.0',
28848
28849		defaults: {
28850			theme     : 'light',          // 'default', dark', 'light'
28851			padding   : 15,					// space inside box, around content
28852			margin    : [30, 55, 30, 55],	// space between viewport and the box
28853			loop      : true,               // Continuous gallery item loop
28854
28855			arrows    : true,
28856			closeBtn  : true,
28857			expander  : !isTouch,
28858
28859			caption : {
28860				type     : 'outside'	// 'float', 'inside', 'outside' or 'over',
28861			},
28862
28863			overlay : {
28864				closeClick : true,      // if true, fancyBox will be closed when user clicks on the overlay
28865				speedIn    : 0,         // duration of fadeIn animation
28866				speedOut   : 250,       // duration of fadeOut animation
28867				showEarly  : true,      // indicates if should be opened immediately or wait until the content is ready
28868				css        : {}			// custom CSS properties
28869			},
28870
28871			helpers : {},				// list of enabled helpers
28872
28873			// Dimensions
28874			width       : 800,
28875			height      : 450,
28876			minWidth    : 100,
28877			minHeight   : 100,
28878			maxWidth    : 99999,
28879			maxHeight   : 99999,
28880			aspectRatio : false,
28881			fitToView   : true,
28882
28883			autoHeight  : true,
28884			autoWidth   : true,
28885			autoResize  : true,
28886
28887			// Location
28888			autoCenter  : !isTouch,
28889			topRatio    : 0.5,
28890			leftRatio   : 0.5,
28891
28892			// Opening animation
28893			openEffect  : 'fade',		// 'elastic', 'fade', 'drop' or 'none'
28894			openSpeed   : 800,
28895			openEasing  : 'easeOutQuad',
28896
28897			// Closing animation
28898			closeEffect : 'fade',		// 'elastic', 'fade', 'drop' or 'none'
28899			closeSpeed  : 500,
28900			closeEasing : 'easeOutQuad',
28901
28902			// Animation for next gallery item
28903			nextEffect : 'fade',		// 'elastic', 'fade', 'drop' or 'none'
28904			nextSpeed  : 500,
28905			nextEasing : 'easeOutQuad',
28906
28907			// Animation for previous gallery item
28908			prevEffect : 'fade',		// 'elastic', 'fade', 'drop' or 'none'
28909			prevSpeed  : 500,
28910			prevEasing : 'easeOutQuad',
28911
28912			// Slideshow
28913			autoPlay   : false,
28914			playSpeed  : 3000,
28915
28916			/*
28917				Advanced
28918			*/
28919
28920			// Callbacks
28921			onCancel     : $.noop, // If canceling
28922			beforeLoad   : $.noop, // Before loading
28923			afterLoad    : $.noop, // After loading
28924			beforeShow   : $.noop, // Before changing in current item
28925			afterShow    : $.noop, // After opening
28926			beforeClose  : $.noop, // Before closing
28927			afterClose   : $.noop,  // After closing
28928
28929			// Properties specific to content type
28930			ajax  : {
28931				dataType : 'html',
28932				headers  : { 'X-fancyBox': true }
28933			},
28934
28935			iframe : {
28936				scrolling : 'auto',
28937				preload   : true
28938			},
28939
28940			swf : {
28941				wmode             : 'transparent',
28942				allowfullscreen   : 'true',
28943				allowscriptaccess : 'always'
28944			},
28945
28946			// Default keyboard
28947			keys  : {
28948				next : {
28949					13 : 'left', // enter
28950					34 : 'up',   // page down
28951					39 : 'left', // right arrow
28952					40 : 'up'    // down arrow
28953				},
28954				prev : {
28955					8  : 'right',  // backspace
28956					33 : 'down',   // page up
28957					37 : 'right',  // left arrow
28958					38 : 'down'    // up arrow
28959				},
28960				close  : [27], // escape key
28961				play   : [32], // space - start/stop slideshow
28962				toggle : [70]  // letter "f" - toggle fullscreen
28963			},
28964
28965			// Default direction
28966			direction : {
28967				next : 'left',
28968				prev : 'right'
28969			},
28970
28971			// HTML templates
28972			tpl: {
28973				wrap     : '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-inner"></div></div>',
28974				iframe   : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true"></iframe>',
28975				error    : '<p class="fancybox-error">{{ERROR}}</p>',
28976				closeBtn : '<a title="{{CLOSE}}" class="fancybox-close" href="javascript:;"></a>',
28977				next     : '<a title="{{NEXT}}" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',
28978				prev     : '<a title="{{PREV}}" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>'
28979			},
28980
28981			// Localization
28982			locale  : 'en',
28983			locales : {
28984				'en' : {
28985					CLOSE      : 'Close',
28986					NEXT       : 'Next',
28987					PREV       : 'Previous',
28988					ERROR      : 'The requested content cannot be loaded. <br/> Please try again later.',
28989					EXPAND     : 'Display actual size',
28990					SHRINK     : 'Fit to the viewport',
28991					PLAY_START : 'Start slideshow',
28992					PLAY_STOP  : 'Pause slideshow'
28993				},
28994				'de' : {
28995					CLOSE      : 'Schliessen',
28996					NEXT       : 'Vorwärts',
28997					PREV       : 'Zurück',
28998					ERROR      : 'Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.',
28999					EXPAND     : '',
29000					SHRINK     : '',
29001					PLAY_START : '',
29002					PLAY_STOP  : ''
29003				}
29004			},
29005
29006			// Override some properties
29007			index     : 0,
29008			content   : null,
29009			href      : null,
29010
29011			// Various
29012			wrapCSS       : '',         // CSS class name for the box
29013			modal         : false,
29014			locked        : true,
29015			preload       : 3,			// Number of gallery images to preload
29016			mouseWheel    : true,		// Enable or disable mousewheel support
29017			scrolling     : 'auto',     // 'yes', 'no', any valid value for CSS "overflow" property
29018			scrollOutside : true		// If trye, fancyBox will try to set scrollbars outside the content
29019		},
29020
29021		// Current state
29022		current  : null,
29023		coming   : null,
29024		group    : [],
29025		index    : 0,
29026		isActive : false,	// Is activated
29027		isOpen   : false,	// Is currently open
29028		isOpened : false,	// Have been fully opened at least once
29029		isMaximized : false,
29030
29031		player : {
29032			timer    : null,
29033			isActive : false
29034		},
29035
29036		// Loaders
29037		ajaxLoad   : null,
29038		imgPreload : null,
29039
29040		// Object containing all helpers
29041		helpers    : {},
29042
29043		// Open fancyBox
29044		open: function( items, options ) {
29045			if (!items) {
29046				return;
29047			}
29048
29049			// Close if already active
29050			if (false === F.close(true)) {
29051				return;
29052			}
29053
29054			if (!$.isPlainObject( options )) {
29055				options = {};
29056			}
29057
29058			F.opts = $.extend(true, {}, F.defaults, options);
29059
29060			F.populate( items );
29061
29062			if (F.group.length) {
29063				F._start( F.opts.index );
29064			}
29065		},
29066
29067		// Add new items to the group
29068		populate : function( items ) {
29069			var group = [];
29070
29071			if ( !$.isArray( items )) {
29072				items = [ items ];
29073			}
29074
29075			// Build group array, each item is object containing element
29076			// and most important attributes - href, title and type
29077			$.each(items, function(i, element) {
29078				var defaults = $.extend(true, {}, F.opts),
29079					item,
29080					obj,
29081					type,
29082					margin,
29083					padding;
29084
29085				if ($.isPlainObject(element)) {
29086					item = element;
29087
29088				} else if (isString(element)) {
29089					item = { href : element };
29090
29091				} else if (isQuery(element) || $.type(element) === 'object' && element.nodeType) {
29092					obj  = $(element);
29093					item = $(obj).get(0);
29094
29095					if (!item.href) {
29096						item = { href : element };
29097					}
29098
29099					item = $.extend({
29100						href    : obj.data('fancybox-href')  || obj.attr('href')  || item.href,
29101						title   : obj.data('fancybox-title') || obj.attr('title') || item.title,
29102						type    : obj.data('fancybox-type'),
29103						element : obj
29104					}, obj.data('fancybox-options') );
29105
29106				} else {
29107					return;
29108				}
29109
29110				// If the type has not specified, then try to guess
29111				if (!item.type && (item.content || item.href)) {
29112					item.type = item.content ? "html" : F.guessType( obj, item.href );
29113				}
29114
29115				// Adjust some defaults depending on content type
29116				type = item.type || F.opts.type;
29117
29118				if (type === 'image' || type === 'swf') {
29119					defaults.autoWidth = defaults.autoHeight = false;
29120					defaults.scrolling = 'visible';
29121				}
29122
29123				if (type === 'image') {
29124					defaults.aspectRatio = true;
29125				}
29126
29127				if (type === 'iframe') {
29128					defaults.autoWidth = false;
29129					defaults.scrolling = isTouch ? 'scroll' : 'visible';
29130				}
29131
29132				if (items.length < 2) {
29133					defaults.margin = 30;
29134				}
29135
29136				item = $.extend(true, {}, defaults, item);
29137
29138				// Recheck some parameters
29139				margin  = item.margin;
29140				padding = item.padding;
29141
29142				// Convert margin and padding properties to array - top, right, bottom, left
29143				if ($.type(margin) === 'number') {
29144					item.margin = [margin, margin, margin, margin];
29145				}
29146
29147				if ($.type(padding) === 'number') {
29148					item.padding = [padding, padding, padding, padding];
29149				}
29150
29151				// 'modal' propery is just a shortcut
29152				if (item.modal) {
29153					$.extend(true, item, {
29154						closeBtn   : false,
29155						closeClick : false,
29156						nextClick  : false,
29157						arrows     : false,
29158						mouseWheel : false,
29159						keys       : null,
29160						overlay : {
29161							closeClick : false
29162						}
29163					});
29164				}
29165
29166				if (item.autoSize !== undefined) {
29167					item.autoWidth = item.autoHeight = !!item.autoSize;
29168				}
29169
29170				if (item.width === 'auto') {
29171					item.autoWidth = true;
29172				}
29173
29174				if (item.height === 'auto') {
29175					item.autoHeight = true;
29176				}
29177
29178				group.push( item );
29179			});
29180
29181			F.group = F.group.concat( group );
29182		},
29183
29184		// Cancel image loading and abort ajax request
29185		cancel: function () {
29186			var coming = F.coming;
29187
29188			if (!coming || false === F.trigger('onCancel')) {
29189				return;
29190			}
29191
29192			F.hideLoading();
29193
29194			if (F.ajaxLoad) {
29195				F.ajaxLoad.abort();
29196			}
29197
29198			if (F.imgPreload) {
29199				F.imgPreload.onload = F.imgPreload.onerror = null;
29200			}
29201
29202			if (coming.wrap) {
29203				removeWrap( coming.wrap );
29204			}
29205
29206			F.ajaxLoad = F.imgPreload = F.coming = null;
29207
29208			// If the first item has been canceled, then clear everything
29209			if (!F.current) {
29210				F._afterZoomOut( coming );
29211			}
29212		},
29213
29214		// Start closing or remove immediately if is opening/closing
29215		close: function (e) {
29216			if (e && $.type(e) === 'object') {
29217				e.preventDefault();
29218			}
29219
29220			F.cancel();
29221
29222			// Do not close if:
29223			//   - the script has not been activated
29224			//   - cancel event has triggered opening a new item
29225			//   - "beforeClose" trigger has returned false
29226			if (!F.isActive || F.coming || false === F.trigger('beforeClose')) {
29227				return;
29228			}
29229
29230			F.unbind();
29231
29232			F.isClosing = true;
29233
29234			if (F.lock) {
29235				F.lock.css('overflow', 'hidden');
29236			}
29237
29238			if (!F.isOpen || e === true) {
29239				F._afterZoomOut();
29240
29241			} else {
29242				F.isOpen = F.isOpened = false;
29243
29244				F.transitions.close();
29245			}
29246		},
29247
29248		prev : function( direction ) {
29249			var current = F.current;
29250
29251			if (current) {
29252				F.jumpto( current.index - 1, (isString(direction) ? direction : current.direction.prev) );
29253			}
29254		},
29255
29256		next : function( direction ) {
29257			var current = F.current;
29258
29259			if (current) {
29260				F.jumpto( current.index + 1, (isString(direction) ? direction : current.direction.next) );
29261			}
29262		},
29263
29264		jumpto : function( index, direction ) {
29265			var current = F.current;
29266
29267			if (!(F.coming && F.coming.index === index)) {
29268				F.cancel();
29269
29270				if (current.index == index) {
29271					direction = null;
29272
29273				} else if (!direction) {
29274					direction = current.direction[ index > current.index ? 'next' : 'prev' ];
29275				}
29276
29277				F.direction = direction;
29278
29279				F._start( index );
29280			}
29281		}
29282	});
29283
29284	$.extend(F, {
29285		guessType : function(item, href) {
29286			var rez  = item && item.prop('class') ? item.prop('class').match(/fancybox\.(\w+)/) : 0,
29287				type = false;
29288
29289			if (rez) {
29290				return rez[1];
29291			}
29292
29293			if (isString(href)) {
29294				if (href.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp)((\?|#).*)?$)/i)) {
29295					type = 'image';
29296
29297				} else if (href.match(/\.(swf)((\?|#).*)?$/i)) {
29298					type = 'swf';
29299
29300				} else if (href.charAt(0) === '#') {
29301					type = 'inline';
29302				}
29303
29304			} else if (isString(item)) {
29305				type = 'html';
29306			}
29307
29308			return type;
29309		},
29310
29311		trigger: function (event, o) {
29312			var ret, obj = o || F.coming || F.current;
29313
29314			if (!obj) {
29315				return;
29316			}
29317
29318			if ($.isFunction( obj[event] )) {
29319				ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1));
29320			}
29321
29322			// Cancel further execution if afterClose callback has opened new instance
29323			if (ret === false || (event === 'afterClose' && F.isActive) ) {
29324				return false;
29325			}
29326
29327			if (obj.helpers) {
29328				$.each(obj.helpers, function (helper, opts) {
29329					var helperObject = F.helpers[helper],
29330						helperOpts;
29331
29332					if (opts && helperObject && $.isFunction(helperObject[event])) {
29333						helperOpts = $.extend(true, {}, helperObject.defaults, opts);
29334
29335						helperObject.opts = helperOpts;
29336
29337						helperObject[event](helperOpts, obj );
29338					}
29339				});
29340			}
29341
29342			$.event.trigger(event);
29343		},
29344
29345		// Center inside viewport
29346		reposition: function (e, object) {
29347			var obj  = object || F.current,
29348				wrap = obj && obj.wrap,
29349				pos;
29350
29351			if (F.isOpen && wrap) {
29352				pos = F._getPosition( obj );
29353
29354				if (e === false || (e && e.type === 'scroll')) {
29355					wrap.stop(true).animate(pos, 200).css('overflow', 'visible');
29356
29357				} else {
29358					wrap.css(pos);
29359				}
29360			}
29361		},
29362
29363		update: function (e) {
29364			var type    = (e && e.type),
29365				timeNow = getTime(),
29366				current = F.current,
29367				width;
29368
29369			if (!current || !F.isOpen ) {
29370				return;
29371			}
29372
29373			if (type === 'scroll') {
29374				if (F.wrap.outerHeight(true) > F.getViewport().h) {
29375					return;
29376				}
29377
29378				if (F.didUpdate) {
29379					clearTimeout( F.didUpdate );
29380				}
29381
29382				F.didUpdate = setTimeout(function() {
29383					F.reposition(e);
29384
29385					F.didUpdate = null;
29386				}, 50);
29387
29388				return;
29389			}
29390
29391			if (F.lock) {
29392				F.lock.css('overflow', 'hidden');
29393			}
29394
29395			F._setDimension();
29396
29397			F.reposition(e);
29398
29399			if (F.lock) {
29400				F.lock.css('overflow', 'auto');
29401			}
29402
29403			// Re-center float type caption
29404			if (current.caption.type === 'float') {
29405				width = F.getViewport().w - (F.wrap.outerWidth(true)  - F.inner.width() );
29406
29407				current.caption.wrap.css('width', width).css('marginLeft', (width * 0.5 - F.inner.width() * 0.5) * -1 );
29408			}
29409
29410			if (current.expander) {
29411				if ( current.canShrink) {
29412					$(".fancybox-expand").show().attr('title', current.locales[ current.locale ].SHRINK  );
29413
29414				} else if (current.canExpand) {
29415					$(".fancybox-expand").show().attr('title', current.locales[ current.locale ].EXPAND   );
29416
29417				} else {
29418					$(".fancybox-expand").hide();
29419				}
29420			}
29421
29422			F.trigger('onUpdate');
29423		},
29424
29425		// Shrink content to fit inside viewport or restore if resized
29426		toggle: function ( action ) {
29427			var current = F.current;
29428
29429			if (current && F.isOpen) {
29430				F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView;
29431
29432				F.update( true );
29433			}
29434		},
29435
29436		hideLoading: function () {
29437			$('#fancybox-loading').remove();
29438		},
29439
29440		showLoading: function () {
29441			var el, view;
29442
29443			F.hideLoading();
29444
29445			el = $('<div id="fancybox-loading"></div>').click(F.cancel).appendTo('body');
29446
29447			if (!F.defaults.fixed) {
29448				view = F.getViewport();
29449
29450				el.css({
29451					position : 'absolute',
29452					top  : (view.h * 0.5) + view.y,
29453					left : (view.w * 0.5) + view.x
29454				});
29455			}
29456		},
29457
29458		getViewport: function () {
29459			var rez;
29460
29461			if (F.lock) {
29462				rez = {
29463					x: F.lock.scrollLeft(),
29464					y: F.lock.scrollTop(),
29465					w: F.lock[0].clientWidth,
29466					h: F.lock[0].clientHeight
29467				};
29468
29469			} else {
29470				rez = {
29471					x: W.scrollLeft(),
29472					y: W.scrollTop(),
29473
29474					// See http://bugs.jquery.com/ticket/6724
29475					w : isTouch && window.innerWidth  ? window.innerWidth  : W.width(),
29476					h : isTouch && window.innerHeight ? window.innerHeight : W.he
29476ight()
29477				};
29478			}
29479
29480			return rez;
29481		},
29482
29483		unbind : function() {
29484			if (isQuery(F.wrap)) {
29485				F.wrap.unbind('.fb');
29486			}
29487
29488			if (isQuery(F.inner)) {
29489				F.inner.unbind('.fb');
29490			}
29491
29492			D.unbind('.fb');
29493			W.unbind('.fb');
29494		},
29495
29496		rebind: function () {
29497			var current = F.current,
29498				keys;
29499
29500			F.unbind();
29501
29502			if (!current || !F.isOpen) {
29503				return;
29504			}
29505
29506			// Changing document height on iOS devices triggers a 'resize' event,
29507			// that can change document height... repeating infinitely
29508			W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update);
29509
29510			keys = current.keys;
29511
29512			if (keys) {
29513				D.bind('keydown.fb', function (e) {
29514					var code   = e.which || e.keyCode,
29515						target = e.target || e.srcElement;
29516
29517					// Skip esc key if loading, because showLoading will cancel preloading
29518					if (code === 27 && F.coming) {
29519						return false;
29520					}
29521
29522					// Ignore key combinations and key events within form elements
29523					if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) {
29524						$.each(keys, function(i, val) {
29525							//if (current.group.length > 1 && val[ code ] !== undefined) {
29526							if (val[ code ] !== undefined) {
29527								e.preventDefault();
29528
29529								if (current.group.length > 1) {
29530									F[ i ]( val[ code ] );
29531								}
29532
29533								return false;
29534							}
29535
29536							if ($.inArray(code, val) > -1) {
29537								e.preventDefault();
29538
29539								if (i === 'play') {
29540									F.slideshow.toggle();
29541								} else {
29542									F[ i ] ();
29543								}
29544
29545								return false;
29546							}
29547						});
29548					}
29549				});
29550			}
29551
29552			F.lastScroll = getTime();
29553
29554			if (current.mouseWheel && F.group.length > 1) {
29555				F.wrap.bind('DOMMouseScroll.fb mousewheel.fb MozMousePixelScroll.fb', function (event) {
29556					var e       = event.originalEvent,
29557						el      = e.target || 0,
29558						delta   = (e.wheelDelta || e.detail || 0),
29559						deltaX  = e.wheelDeltaX || 0,
29560						deltaY  = e.wheelDeltaY || 0,
29561						now     = getTime();
29562
29563					if (((el && el.style && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight)))) ) {
29564						return;
29565					}
29566
29567					if (delta === 0 || (F.current && F.current.canShrink)) {
29568						return;
29569					}
29570
29571					e.stopPropagation();
29572
29573					if (F.lastScroll && (now - F.lastScroll) < 80) {
29574						F.lastScroll = now;
29575						return;
29576					}
29577
29578					F.lastScroll = now;
29579
29580					if (e.axis) {
29581						if (e.axis === e.HORIZONTAL_AXIS) {
29582							deltaX = delta * -1;
29583
29584						} else if (e.axis === e.VERTICAL_AXIS) {
29585							deltaY = delta * -1;
29586						}
29587					}
29588
29589					if ( deltaX === 0 ) {
29590						if (deltaY > 0) {
29591							F.prev( 'down' );
29592
29593						} else {
29594							F.next( 'up' );
29595						}
29596
29597					} else {
29598						if (deltaX > 0) {
29599							F.prev( 'right' );
29600
29601						} else {
29602							F.next( 'left' );
29603						}
29604					}
29605				});
29606			}
29607
29608			F.touch.init();
29609		},
29610
29611		rebuild : function() {
29612			var current = F.current;
29613
29614			current.wrap.find('.fancybox-nav, .fancybox-close, .fancybox-expand').remove();
29615
29616			// Create navigation arrows
29617			if (current.arrows && F.group.length > 1) {
29618				if (current.loop || current.index > 0) {
29619					$( F._translate( current.tpl.prev) ).appendTo(F.inner).bind('click.fb', F.prev);
29620				}
29621
29622				if (current.loop || current.index < F.group.length - 1) {
29623					$( F._translate( current.tpl.next) ).appendTo(F.inner).bind('click.fb', F.next);
29624				}
29625			}
29626
29627			// Create a close button
29628			if (current.closeBtn) {
29629				$( F._translate( current.tpl.closeBtn) ).appendTo(F.wrap).bind('click.fb', F.close);
29630			}
29631
29632			// Add expand button to image
29633			if (current.expander && current.type === 'image') {
29634				$('<a title="Expand image" class="fancybox-expand" href="javascript:;"></a>')
29635					.appendTo( F.inner )
29636					.bind('click.fb', F.toggle);
29637
29638				if ( !current.canShrink && !current.canExpand) {
29639
29640				}
29641			}
29642		},
29643
29644		// Create upcoming object and prepare for loading the content
29645		_start: function( index ) {
29646			var coming,
29647				type;
29648
29649			// Check index and get object from the groups
29650			if (F.opts.loop) {
29651				if (index < 0) {
29652					index = F.group.length + (index % F.group.length);
29653				}
29654
29655				index = index % F.group.length;
29656			}
29657
29658			coming = F.group[ index ];
29659
29660			if (!coming) {
29661				return false;
29662			}
29663
29664			// Add all properties
29665			coming = $.extend(true, {}, F.opts, coming);
29666
29667			/*
29668			 * Add reference to the group, so it`s possible to access from callbacks, example:
29669			 * afterLoad : function() {
29670			 *     this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
29671			 * }
29672			 */
29673
29674			coming.group  = F.group;
29675			coming.index  = index;
29676
29677			// Give a chance for callback or helpers to update coming item (type, title, etc)
29678			F.coming = coming;
29679
29680			if (false === F.trigger('beforeLoad')) {
29681				F.coming = null;
29682
29683				return;
29684			}
29685
29686			F.isActive = true;
29687
29688			// Build the neccessary markup
29689			F._build();
29690
29691			// If user will press the escape-button, the request will be canceled
29692			D.bind('keydown.loading', function(e) {
29693				if ((e.which || e.keyCode) === 27) {
29694					D.unbind('.loading');
29695
29696					e.preventDefault();
29697
29698					F.cancel();
29699				}
29700			});
29701
29702			// Show overlay
29703			if (coming.overlay && coming.overlay.showEarly) {
29704				F.overlay.open( coming.overlay );
29705			}
29706
29707			// Load content
29708			type = coming.type;
29709
29710			if (type === 'image') {
29711				F._loadImage();
29712
29713			} else if (type === 'ajax') {
29714				F._loadAjax();
29715
29716			} else if (type === 'iframe') {
29717				F._loadIframe();
29718
29719			} else if (type === 'inline') {
29720				F._loadInline();
29721
29722			} else if (type === 'html' || type === 'swf') {
29723				F._afterLoad();
29724
29725			} else {
29726				F._error();
29727			}
29728		},
29729
29730		_build : function() {
29731			var coming  = F.coming,
29732				captionType = coming.caption.type,
29733				wrap,
29734				inner,
29735				scrollV,
29736				scrollH;
29737
29738			coming.wrap  = wrap  = $('<div class="fancybox-wrap"></div>').appendTo( coming.parent || 'body' ).addClass('fancybox-' + coming.theme);
29739			coming.inner = inner = $('<div class="fancybox-inner"></div>').appendTo( wrap );
29740
29741			coming[ captionType === 'outside' || captionType === 'float' ? 'inner' : 'wrap' ].addClass('fancybox-skin fancybox-' + coming.theme + '-skin');
29742
29743			if (coming.locked && coming.overlay && F.defaults.fixed) {
29744				if (!F.lock) {
29745					F.lock = $('<div id="fancybox-lock"></div>').appendTo( wrap.parent() );
29746				}
29747
29748				F.lock.unbind().append( wrap );
29749
29750				if (coming.overlay.closeClick) {
29751					F.lock.click(function(e) {
29752						if ($(e.target).is(F.lock)) {
29753							F.close();
29754						}
29755					});
29756				}
29757
29758				// Compensate missing page scrolling by increasing margin
29759				if (D.height() > W.height() || H.css('overflow-y') === 'scroll') {
29760					$('*:visible').filter(function(){
29761						return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && $(this).attr('id') !== "fancybox-lock");
29762					}).addClass('fancybox-margin');
29763
29764					H.addClass('fancybox-margin');
29765				}
29766
29767				// Workaround for FF jumping bug
29768				scrollV = W.scrollTop();
29769				scrollH = W.scrollLeft();
29770
29771				H.addClass('fancybox-lock');
29772
29773				W.scrollTop( scrollV ).scrollLeft( scrollH );
29774			}
29775
29776			F.trigger('onReady');
29777		},
29778
29779		_error: function ( type ) {
29780			if (!F.coming) {
29781				return;
29782			}
29783
29784			$.extend(F.coming, {
29785				type       : 'html',
29786				autoWidth  : true,
29787				autoHeight : true,
29788				closeBtn   : true,
29789				minWidth   : 0,
29790				minHeight  : 0,
29791				padding    : [15, 15, 15, 15],
29792				scrolling  : 'visible',
29793				hasError   : type,
29794				content    : F._translate( F.coming.tpl.error )
29795			});
29796
29797			F._afterLoad();
29798		},
29799
29800		_loadImage: function () {
29801			// Reset preload image so it is later possible to check "complete" property
29802			var img = F.imgPreload = new Image();
29803
29804			img.onload = function () {
29805				this.onload = this.onerror = null;
29806
29807				$.extend(F.coming, {
29808					width   : this.width,
29809					height  : this.height,
29810					content : $(this).addClass('fancybox-image')
29811				});
29812
29813				F._afterLoad();
29814			};
29815
29816			img.onerror = function () {
29817				this.onload = this.onerror = null;
29818
29819				F._error( 'image' );
29820			};
29821
29822			img.src = F.coming.href;
29823
29824			if (img.complete !== true || img.width < 1) {
29825				F.showLoading();
29826			}
29827		},
29828
29829		_loadAjax: function () {
29830			var coming = F.coming,
29831				href   = coming.href,
29832				hrefParts,
29833				selector;
29834
29835			hrefParts = href.split(/\s+/, 2);
29836			href      = hrefParts.shift();
29837			selector  = hrefParts.shift();
29838
29839			F.showLoading();
29840
29841			F.ajaxLoad = $.ajax($.extend({}, coming.ajax, {
29842				url: coming.href,
29843				error: function (jqXHR, textStatus) {
29844					if (F.coming && textStatus !== 'abort') {
29845						F._error( 'ajax', jqXHR );
29846
29847					} else {
29848						F.hideLoading();
29849					}
29850				},
29851				success: function (data, textStatus) {
29852					if (textStatus === 'success') {
29853						if (selector) {
29854							data = $('<div>').html(data).find(selector);
29855						}
29856
29857						coming.content = data;
29858
29859						F._afterLoad();
29860					}
29861				}
29862			}));
29863		},
29864
29865		_loadIframe: function() {
29866			var coming = F.coming,
29867				iframe;
29868
29869			coming.content = iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime()))
29870				.attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling);
29871
29872			if (coming.iframe.preload) {
29873				F.showLoading();
29874
29875				F._setDimension( coming );
29876
29877				coming.wrap.addClass('fancybox-tmp');
29878
29879				iframe.one('load.fb', function() {
29880					if (coming.iframe.preload) {
29881						$(this).data('ready', 1);
29882
29883						$(this).bind('load.fb', F.update);
29884
29885						F._afterLoad();
29886					}
29887				});
29888			}
29889
29890			iframe.attr('src', coming.href).appendTo(coming.inner);
29891
29892			if (!coming.iframe.preload) {
29893				F._afterLoad();
29894
29895			} else if (iframe.data('ready') !== 1) {
29896				F.showLoading();
29897			}
29898		},
29899
29900		_loadInline : function() {
29901			var coming = F.coming,
29902				href   = coming.href;
29903
29904			coming.content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7
29905
29906			if (coming.content.length) {
29907				F._afterLoad();
29908
29909			} else {
29910				F._error();
29911			}
29912		},
29913
29914		_preloadImages: function() {
29915			var group   = F.group,
29916				current = F.current,
29917				len     = group.length,
29918				cnt     = current.preload ? Math.min(current.preload, len - 1) : 0,
29919				item,
29920				i;
29921
29922			for (i = 1; i <= cnt; i += 1) {
29923				item = group[ (current.index + i ) % len ];
29924
29925				if (item && item.type === 'image' && item.href) {
29926					new Image().src = item.href;
29927				}
29928			}
29929		},
29930
29931		_afterLoad : function() {
29932			var current  = F.coming,
29933				previous = F.current;
29934
29935			D.unbind('.loading');
29936
29937			if (!current || F.isActive === false || false === F.trigger('afterLoad', current, previous)) {
29938				F.hideLoading();
29939
29940				if (current && current.wrap) {
29941					removeWrap( current.wrap );
29942				}
29943
29944				if (!previous) {
29945					F._afterZoomOut( current );
29946				}
29947
29948				F.coming = null;
29949
29950				return;
29951			}
29952
29953			$.extend(F, {
29954				wrap     : current.wrap.addClass('fancybox-type-' + current.type + ' fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-' + current.theme + '-' +  (isTouch ? 'mobile' : 'desktop')  + ' ' + current.wrapCSS),
29955				inner    : current.inner,
29956				current  : current,
29957				previous : previous
29958			});
29959
29960			// Set content, margin/padding, caption, etc
29961			F._prepare();
29962
29963			// Give a chance for helpers or callbacks to update elements
29964			F.trigger('beforeShow', current, previous);
29965
29966			F.isOpen = false;
29967			F.coming = null;
29968
29969			// Set initial dimension
29970			F._setDimension();
29971
29972			F.hideLoading();
29973
29974			// Open overlay if is not yet open
29975			if (current.overlay && !F.overlay.el) {
29976				F.overlay.open( current.overlay );
29977			}
29978
29979			F.transitions.open();
29980		},
29981
29982		_prepare : function() {
29983			var current     = F.current,
29984				content     = current.content || '',
29985				wrap        = current.wrap,
29986				inner       = current.inner,
29987				margin      = current.margin,
29988				padding     = current.padding,
29989				href        = current.href,
29990				type        = current.type,
29991				scrolling   = current.scrolling,
29992				caption     = current.caption,
29993				captionText = current.title,
29994				captionType = caption.type,
29995				placeholder = 'fancybox-placeholder',
29996				display     = 'fancybox-display',
29997				embed;
29998
29999			if (type !== 'iframe' && isQuery(content) && content.length) {
30000				if (!content.data(placeholder)) {
30001					content.data(display, content.css('display'))
30002						.data(placeholder, $('<div class="' + placeholder + '"></div>').insertAfter( content ).hide() );
30003				}
30004
30005				content = content.show().detach();
30006
30007				current.wrap.bind('onReset', function () {
30008					if ($(this).find(content).length) {
30009						content.css('display', content.data(display))
30010							.replaceAll( content.data(placeholder) )
30011							.data(placeholder, false)
30012							.data(display, false);
30013					}
30014				});
30015			}
30016
30017			if (type === 'swf') {
30018				content = '<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="' + href + '"></param>';
30019				embed   = '';
30020
30021				$.each(current.swf, function(name, val) {
30022					content += '<param name="' + name + '" value="' + val + '"></param>';
30023					embed   += ' ' + name + '="' + val + '"';
30024				});
30025
30026				content += '<embed src="' + href + '" type="application/x-shockwave-flash" width="100%" height="100%"' + embed + '></embed></object>';
30027			}
30028
30029			if (!(isQuery(content) && content.parent().is(current.inner))) {
30030				current.inner.append( content );
30031
30032				current.content = current.inner.children(':last');
30033			}
30034
30035			// Add margin / padding
30036			$.each(["Top", "Right", "Bottom", "Left"], function(i, v) {
30037				if (margin[ i ]) {
30038					wrap.css('margin' + v, getValue(margin[ i ]));
30039				}
30040
30041				if (padding[ i ]) {
30042					if (!(v === 'Bottom' && captionType === 'outside')) {
30043						wrap.css('padding' + v, getValue(padding[ i ])  );
30044					}
30045
30046					if (captionType === 'outside' || captionType === 'float') {
30047
30048						inner.css('border' + v + 'Width', getValue(padding[ i ]));
30049
30050						if (v === 'Top' || v === 'Left') {
30051							inner.css('margin' + v, getValue(padding[ i ] * -1));
30052						}
30053					}
30054				}
30055			});
30056
30057			// Add caption
30058			if ($.isFunction(captionText)) {
30059				captionText = captionText.call(current.element, current);
30060			}
30061
30062			if (isString(captionText) && $.trim(captionText) !== '') {
30063				current.caption.wrap = $('<div class="fancybox-title fancybox-title-' + captionType + '-wrap">' + captionText + '</div>').appendTo( current[ captionType === 'over' ? 'inner' : 'wrap' ] );
30064
30065				if (captionType === 'float') {
30066					current.caption.wrap.width( F.getViewport().w - (F.wrap.outerWidth(true)  - F.inner.width() ) ).wrapInner('<div></div>');
30067				}
30068			}
30069		},
30070
30071		_setDimension: function( object ) {
30072			var view      = F.getViewport(),
30073				current   = object || F.current,
30074				wrap      = current.wrap,
30075				inner     = current.inner,
30076				width     = current.width,
30077				height    = current.height,
30078				minWidth  = current.minWidth,
30079				minHeight = current.minHeight,
30080				maxWidth  = current.maxWidth,
30081				maxHeight = current.maxHeight,
30082				margin    = current.margin,
30083				scrollOut = current.scrollOutside ? current.scrollbarWidth : 0,
30084				margin    = current.margin,
30085				padding   = current.padding,
30086				scrolling = current.scrolling,
30087				steps     = 1,
30088				scrollingX,
30089				scrollingY,
30090				hSpace,
30091				wSpace,
30092				origWidth,
30093				origHeight,
30094				ratio,
30095				iframe,
30096				body,
30097				maxWidth_,
30098				maxHeight_,
30099				width_,
30100				height_,
30101				canShrink,
30102				canExpand;
30103
30104			// Set scrolling
30105			scrolling  = scrolling.split(',');
30106			scrollingX = scrolling[0];
30107			scrollingY = scrolling[1] || scrollingX;
30108
30109			current.inner
30110				.css('overflow-x', scrollingX === 'yes' ? 'scroll' : (scrollingX === 'no' ? 'hidden' : scrollingX))
30111				.css('overflow-y', scrollingY === 'yes' ? 'scroll' : (scrollingY === 'no' ? 'hidden' : scrollingY));
30112
30113			wSpace = margin[1] + margin[3] + padding[1] + padding[3];
30114			hSpace = margin[0] + margin[2] + padding[0] + padding[2];
30115
30116			// Calculations for the content
30117			minWidth  = getScalar( isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth );
30118			maxWidth  = getScalar( isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth );
30119
30120			minHeight = getScalar( isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight );
30121			maxHeight = getScalar( isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight );
30122
30123			origWidth  = getScalar( isPercentage(width)  ? getScalar(width,  'w') - wSpace : width  );
30124			origHeight = getScalar( isPercentage(height) ? getScalar(height, 'h') - hSpace : height );
30125
30126			if (current.fitToView) {
30127				maxWidth  = Math.min(maxWidth,  getScalar('100%', 'w') - wSpace );
30128				maxHeight = Math.min(maxHeight, getScalar('100%', 'h') - hSpace );
30129			}
30130
30131			maxWidth_  = view.w;
30132			maxHeight_ = view.h;
30133
30134			if (current.type === 'iframe') {
30135				iframe = current.content;
30136
30137				wrap.removeClass('fancybox-tmp');
30138
30139				if ((current.autoWidth || current.autoHeight) && iframe && iframe.data('ready') === 1) {
30140
30141					try {
30142						if (iframe[0].contentWindow && iframe[0].contentWindow.document.location) {
30143							body = iframe.contents().find('body');
30144
30145							inner.addClass( 'fancybox-tmp' );
30146
30147							inner.width( screen.width - wSpace ).height( 99999 );
30148
30149							if (scrollOut) {
30150								body.css('overflow-x', 'hidden');
30151							}
30152
30153							if (current.autoWidth) {
30154								origWidth = body.outerWidth(true);
30155							}
30156
30157							if (current.autoHeight) {
30158								origHeight = body.outerHeight(true);
30159							}
30160
30161							inner.removeClass( 'fancybox-tmp' );
30162						}
30163
30164					} catch (e) {}
30165				}
30166
30167			} else if ( (current.autoWidth || current.autoHeight) && !(current.type === 'image' || current.type === 'swf') ) {
30168				inner.addClass( 'fancybox-tmp' );
30169
30170				// Set width or height in case we need to calculate only one dimension
30171				if (current.autoWidth) {
30172					inner.width( 'auto' );
30173
30174				} else {
30175					inner.width( maxWidth );
30176				}
30177
30178				if (current.autoHeight) {
30179					inner.height( 'auto' );
30180
30181				} else {
30182					inner.height( maxHeight );
30183				}
30184
30185				if (current.autoWidth) {
30186					origWidth = inner[0].scrollWidth || inner.width();
30187				}
30188
30189				if (current.autoHeight) {
30190					origHeight = inner[0].scrollHeight || inner.height();
30191				}
30192
30193				inner.removeClass( 'fancybox-tmp' );
30194			}
30195
30196			width  = origWidth;
30197			height = origHeight;
30198			ratio  = origWidth / origHeight;
30199
30200			if (!current.autoResize) {
30201				wrap.css({
30202					width  : getValue( width ),
30203					height : 'auto'
30204				});
30205
30206				inner.css({
30207					width  : getValue( width ),
30208					height : getValue( height )
30209				});
30210				return;
30211			}
30212
30213			if (current.aspectRatio) {
30214				if (width > maxWidth) {
30215					width  = maxWidth;
30216					height = width / ratio;
30217				}
30218
30219				if (height > maxHeight) {
30220					height = maxHeight;
30221					width  = height * ratio;
30222				}
30223
30224				if (width < minWidth) {
30225					width  = minWidth;
30226					height = width / ratio;
30227				}
30228
30229				if (height < minHeight) {
30230					height = minHeight;
30231					width  = height * ratio;
30232				}
30233
30234			} else {
30235				width = Math.max(minWidth, Math.min(width, maxWidth));
30236
30237				if (current.autoHeight && current.type !== 'iframe') {
30238					inner.width( width );
30239
30240					origHeight = height = inner[0].scrollHeight;
30241				}
30242
30243				height = Math.max(minHeight, Math.min(height, maxHeight));
30244			}
30245
30246			// Wrap element has to have fixed width, because long title can expand it
30247			wrap.css({
30248				width  : getValue( width ),
30249				height : 'auto'
30250			});
30251
30252			inner.css({
30253				width  : getValue( width ),
30254				height : getValue( height )
30255			});
30256
30257			width_  = getScalar( wrap.outerWidth(true) );
30258			height_ = getScalar( wrap.outerHeight(true) );
30259
30260			if (current.fitToView) {
30261				// Since we do not know how many lines will be at the final, we need to
30262				// resize box till it fits inside max dimensions
30263				if (current.aspectRatio) {
30264					while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) {
30265						if (steps++ > 30) {
30266							break;
30267						}
30268
30269						height = Math.max(minHeight, Math.min(maxHeight, height - 10));
30270						width  = getScalar(height * ratio);
30271
30272						if (width < minWidth) {
30273							width  = minWidth;
30274							height = getScalar(width / ratio);
30275						}
30276
30277						if (width > maxWidth) {
30278							width  = maxWidth;
30279							height = getScalar(width / ratio);
30280						}
30281
30282						wrap.css({
30283							width  : getValue( width )
30284						});
30285
30286						inner.css({
30287							width  : getValue( width ),
30288							height : getValue( height )
30289						});
30290
30291						width_  = getScalar( wrap.outerWidth(true) );
30292						height_ = getScalar( wrap.outerHeight(true) );
30293					}
30294
30295				} else {
30296					width  = Math.max(minWidth,  Math.min(width,  width  - (width_  - maxWidth_  )));
30297					height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_ )));
30298				}
30299			}
30300
30301
30302			if (scrollOut && scrollingX === 'auto' && (height < inner[0].scrollHeight || (isQuery(current.content) && current.content[0] && height < current.content[0].offsetHeight)) && (width + wSpace + scrollOut) < maxWidth) {
30303				width += scrollOut;
30304			}
30305
30306			wrap.css({
30307				width  : width
30308			});
30309
30310			inner.css({
30311				width  : getValue( width ),
30312				height : getValue( height )
30313			});
30314
30315			width_  = getScalar( wrap.outerWidth(true) );
30316			height_ = getScalar( wrap.outerHeight(true) );
30317
30318			canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight;
30319			canExpand = (width_ < maxWidth_ || height_ < maxHeight_) && ( current.aspectRatio ? (width < maxWidth && height < maxHeight && width < origWidth && height < origHeight) : ((width < maxWidth || height < maxHeight) && (width < origWidth || height < origHeight)) );
30320
30321			current.canShrink = canShrink;
30322			current.canExpand = canExpand;
30323
30324			if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) {
30325				inner.height('auto');
30326			}
30327		},
30328
30329		_getPosition: function( object ) {
30330			var obj   = object || F.current,
30331				wrap  = obj.wrap,
30332				view  = F.getViewport(),
30333				pos   = {},
30334				top   = view.y,
30335				left  = view.x;
30336
30337			pos = {
30338				top    : getValue( Math.max(top,  top  + ((view.h - wrap.outerHeight(true)) * obj.topRatio)) ),
30339				left   : getValue( Math.max(left, left + ((view.w - wrap.outerWidth(true))  * obj.leftRatio)) ),
30340				width  : getValue( wrap.width() ),
30341				height : getValue( wrap.height() )
30342			};
30343
30344			return pos;
30345		},
30346
30347		_afterZoomIn : function() {
30348			var current   = F.current;
30349
30350			if (!current) {
30351				return;
30352			}
30353
30354			if (F.lock) {
30355				F.lock.css('overflow', 'auto');
30356			}
30357
30358			F.isOpen = F.isOpened = true;
30359
30360			F.rebuild();
30361
30362			F.rebind();
30363
30364			if (current.caption && current.caption.wrap) {
30365				current.caption.wrap.show().css({
30366					'visibility' : 'visible',
30367					'opacity'    : 0,
30368					'left'       : 0
30369				})
30370				.animate({opacity:1}, "fast");
30371			}
30372
30373			F.update();
30374
30375			F.wrap.css('overflow', 'visible').addClass('fancybox-open').focus();
30376
30377			F[ F.wrap.hasClass('fancybox-skin') ? 'wrap' : 'inner' ].addClass('fancybox-' + current.theme + '-skin-open');
30378
30379			if (current.caption && current.caption.wrap) {
30380				current.caption.wrap.show().css('left', 0).animate({opacity:1}, "fast");
30381			}
30382
30383			// Add empty element to simulate bottom margin, this trick helps to avoid extra element
30384			if (current.margin[2] > 0) {
30385				$('<div class="fancybox-spacer"></div>').css('height', getValue( current.margin[2] - 2) ).appendTo( F.wrap );
30386			}
30387
30388			F.trigger('afterShow');
30389
30390			F._preloadImages();
30391
30392			if (current.autoPlay && !F.slideshow.isActive) {
30393				F.slideshow.start();
30394			}
30395		},
30396
30397		_afterZoomOut : function(obj) {
30398			var cleanup = function() {
30399				removeWrap('.fancybox-wrap');
30400			};
30401
30402			F.hideLoading();
30403
30404			obj = obj || F.current;
30405
30406			if (obj && obj.wrap) {
30407				obj.wrap.hide();
30408			}
30409
30410			$.extend(F, {
30411				group     : [],
30412				opts      : {},
30413				coming    : null,
30414				current   : null,
30415				isActive  : false,
30416				isOpened  : false,
30417				isOpen    : false,
30418				isClosing : false,
30419				wrap      : null,
30420				skin      : null,
30421				inner     : null
30422			});
30423
30424			F.trigger('afterClose', obj);
30425
30426			if (!F.coming && !F.current) {
30427				if (obj.overlay) {
30428					F.overlay.close( obj.overlay, cleanup );
30429				} else {
30430					cleanup();
30431				}
30432			}
30433		},
30434
30435		_translate : function( str ) {
30436			var obj = F.coming || F.current,
30437				arr = obj.locales[ obj.locale ];
30438
30439			return str.replace(/\{\{(\w+)\}\}/g, function(match, n) {
30440				var value = arr[n];
30441
30442				if (value === undefined) {
30443					return match;
30444				}
30445
30446				return value;
30447			});
30448		}
30449	});
30450
30451	/*
30452	 *	Transition object
30453	 */
30454
30455	F.transitions = {
30456		_getOrig: function( object ) {
30457			var obj     = object || F.current,
30458				wrap    = obj.wrap,
30459				element = obj.element,
30460				orig    = obj.orig,
30461				view    = F.getViewport(),
30462				pos     = {},
30463				width   = 50,
30464				height  = 50;
30465
30466			if (!orig && element && element.is(':visible')) {
30467				orig = element.find('img:first:visible');
30468
30469				if (!orig.length) {
30470					orig = element;
30471				}
30472			}
30473
30474			// If there is no orig element, maybe only the first thumbnail is visible
30475			if (!orig && obj.group[0].element) {
30476				orig = obj.group[0].element.find('img:visible:first');
30477			}
30478
30479			if (isQuery(orig) && orig.is(':visible')) {
30480				pos = orig.offset();
30481
30482				if (orig.is('img')) {
30483					width  = orig.outerWidth();
30484					height = orig.outerHeight();
30485				}
30486
30487				if (F.lock) {
30488					pos.top  -= W.scrollTop();
30489					pos.left -= W.scrollLeft();
30490				}
30491
30492			} else {
30493				pos.top  = view.y + (view.h - height) * obj.topRatio;
30494				pos.left = view.x + (view.w - width)  * obj.leftRatio;
30495			}
30496
30497			pos = {
30498				top      : getValue( pos.top  - (wrap.outerHeight(true) - wrap.height() ) * 0.5 ),
30499				left     : getValue( pos.left - (wrap.outerWidth(true)  - wrap.width() )  * 0.5 ),
30500				width    : getValue( width ),
30501				height   : getValue( height )
30502			};
30503
30504			return pos;
30505		},
30506
30507		_getCenter: function( object ) {
30508			var obj   = object || F.current,
30509				wrap  = obj.wrap,
30510				view  = F.getViewport(),
30511				pos   = {},
30512				top   = view.y,
30513				left  = view.x;
30514
30515			pos = {
30516				top    : getValue( Math.max(top,  top  + ((view.h - wrap.outerHeight(true)) * obj.topRatio)) ),
30517				left   : getValue( Math.max(left, left + ((view.w - wrap.outerWidth(true))  * obj.leftRatio)) ),
30518				width  : getValue( wrap.width() ),
30519				height : getValue( wrap.height() )
30520			};
30521
30522			return pos;
30523		},
30524
30525		_prepare : function( object, forClosing ) {
30526			var obj   = object || F.current,
30527				wrap  = obj.wrap,
30528				inner = obj.inner;
30529
30530			// Little trick to avoid animating both elements and to improve performance
30531			wrap.height( wrap.height() );
30532
30533			inner.css({
30534				'width'  : (inner.width() *  100 / wrap.width() )  + '%',
30535				'height' : (Math.floor( (inner.height() * 100 / wrap.height() ) * 100 ) / 100 ) + '%'
30536			});
30537
30538			if (forClosing === true) {
30539				wrap.find('.fancybox-title, .fancybox-spacer, .fancybox-close, .fancybox-nav').remove();
30540			}
30541
30542			inner.css('overflow', 'hidden');
30543		},
30544
30545		fade : function( object, stage ) {
30546			var pos = this._getCenter( object ),
30547				opa = {opacity: 0};
30548
30549			return ((stage === 'open' || stage === 'changeIn') ? [ $.extend(pos, opa), {opacity: 1} ] : [ {}, opa ]);
30550		},
30551
30552		drop : function( object, stage ) {
30553			var a = $.extend(this._getCenter( object ), {opacity: 1}),
30554				b = $.extend({}, a, {opacity: 0, top: getValue( Math.max( F.getViewport().y - object.margin[0], getScalar( a.top ) - 200 ) )});
30555
30556			return ((stage === 'open' || stage === 'changeIn') ? [ b, a ] : [ {}, b ]);
30557		},
30558
30559		elastic : function( object, stage ) {
30560			var wrap      = object.wrap,
30561				margin    = object.margin,
30562				view      = F.getViewport(),
30563				direction = F.direction,
30564				pos       = this._getCenter( object ),
30565				from      = $.extend({}, pos),
30566				to        = $.extend({}, pos),
30567				prop,
30568				amount,
30569				value;
30570
30571			if (stage === 'open') {
30572				from = this._getOrig( object );
30573
30574			} else if (stage === 'close') {
30575				from = {};
30576				to   = this._getOrig( object );
30577
30578			} else if (direction) {
30579				// Calculate max distance and try to avoid scrollbars
30580				prop    = (direction === 'up' || direction === 'down') ? 'top' : 'left';
30581				amount  = (direction === 'up' || direction === 'left') ? 200 : -200;
30582
30583				if (stage === 'changeIn') {
30584					value = getScalar(from[ prop ]) + amount;
30585
30586					if (direction === 'left') {
30587						// from viewport right to center
30588						value = Math.min( value, view.x + view.w - margin[3] - wrap.outerWidth() - 1 );
30589
30590					} else if (direction === 'right') {
30591						// from viewport left to center
30592						value = Math.max( value, view.x - margin[1] );
30593
30594					} else if (direction === 'up') {
30595						// from viewport bottom to center
30596						value = Math.min( value, view.y + view.h - margin[0] - wrap.outerHeight() - 1);
30597
30598					} else {
30599						// down - from viewport top to center
30600						value = Math.max( value, view.y - margin[2] );
30601					}
30602
30603					from[ prop ] = value;
30604
30605				} else {
30606					value = getScalar(wrap.css(prop)) - amount;
30607					from  = {};
30608
30609					if (direction === 'left') {
30610						// from viewport center to left
30611						value = Math.max( value, view.x - margin[3] );
30612
30613					} else if (direction === 'right') {
30614						// from viewport center to right
30615						value = Math.min( value, view.x + view.w - margin[1]  - wrap.outerWidth() - 1 );
30616
30617					} else if (direction === 'up') {
30618						// from viewport center to top
30619						value = Math.max( value, view.y - margin[0]  );
30620
30621					} else {
30622						// down - from center to bottom
30623						value = Math.min( value, view.y + view.h - margin[2] - wrap.outerHeight() - 1 );
30624					}
30625
30626					to[ prop ] = value;
30627				}
30628			}
30629
30630			if (stage === 'open' || stage === 'changeIn') {
30631				from.opacity = 0;
30632				to.opacity   = 1;
30633
30634			} else {
30635				to.opacity   = 0;
30636			}
30637
30638			return [ from, to ];
30639		},
30640
30641		open : function() {
30642			var current   = F.current,
30643				previous  = F.previous,
30644				direction = F.direction,
30645				effect,
30646				pos,
30647				speed,
30648				easing,
30649				stage;
30650
30651			if (previous) {
30652				previous.wrap.stop(true).removeClass('fancybox-opened');
30653			}
30654
30655    		if ( F.isOpened ) {
30656    			effect = current.nextEffect,
30657				speed  = current.nextSpeed;
30658				easing = current.nextEasing;
30659				stage  = 'changeIn';
30660
30661			} else {
30662				effect = current.openEffect;
30663				speed  = current.openSpeed;
30664				easing = current.openEasing;
30665				stage  = 'open';
30666			}
30667
30668			/*
30669			 *	Open current item
30670			 */
30671
30672			if (effect === 'none') {
30673				F._afterZoomIn();
30674
30675			} else {
30676				pos = this[ effect ]( current, stage );
30677
30678				if (effect === 'elastic') {
30679					this._prepare( current );
30680				}
30681
30682				current.wrap.css( pos[ 0 ] );
30683
30684				current.wrap.animate(
30685					pos[ 1 ],
30686					speed,
30687					easing,
30688					F._afterZoomIn
30689				);
30690			}
30691
30692			/*
30693			 *	Close previous item
30694			 */
30695			if (previous) {
30696				if (!F.isOpened || previous.prevEffect === 'none') {
30697					// Remove previous item if it has not fully opened
30698					removeWrap( $('.fancybox-wrap').not( current.wrap ) );
30699
30700				} else {
30701					previous.wrap.stop(true).removeClass('fancybox-opened');
30702
30703					pos = this[ previous.prevEffect ]( previous, 'changeOut' );
30704
30705					this._prepare( previous, true );
30706
30707					previous.wrap.animate(
30708						pos[ 1 ],
30709						previous.prevSpeed,
30710						previous.prevEasing,
30711						function() {
30712							removeWrap( previous.wrap );
30713						}
30714					);
30715				}
30716			}
30717		},
30718
30719		close : function() {
30720			var current  = F.current,
30721				wrap     = current.wrap.stop(true).removeClass('fancybox-opened'),
30722				effect   = current.closeEffect,
30723				pos;
30724
30725			if (effect === 'none') {
30726				return F._afterZoomOut();
30727			}
30728
30729			this._prepare( current, true );
30730
30731			pos = this[ effect ]( current, 'close' );
30732
30733			wrap.addClass('fancybox-animating')
30734				.animate(
30735					pos[ 1 ],
30736					current.closeSpeed,
30737					current.closeEasing,
30738					F._afterZoomOut
30739				);
30740		}
30741	};
30742
30743	/*
30744	 *	Slideshow object
30745	 */
30746
30747	F.slideshow = {
30748		_clear : function () {
30749			if (this._timer) {
30750				clearTimeout(this._timer);
30751			}
30752		},
30753		_set : function () {
30754			this._clear();
30755
30756			if (F.current && this.isActive) {
30757				this._timer = setTimeout(F.next, this._speed);
30758			}
30759		},
30760
30761		_timer   : null,
30762		_speed   : null,
30763
30764		isActive : false,
30765
30766		start : function ( speed ) {
30767			var current = F.current;
30768
30769			if (current && (current.loop || current.index < current.group.length - 1)) {
30770				this.stop();
30771
30772				this.isActive = true;
30773				this._speed   = speed || current.playSpeed;
30774
30775				D.bind({
30776					'beforeLoad.player' : $.proxy(this._clear, this),
30777					'onUpdate.player'   : $.proxy(this._set, this),
30778					'onCancel.player beforeClose.player' : $.proxy(this.stop, this)
30779				});
30780
30781				this._set();
30782
30783				F.trigger('onPlayStart');
30784			}
30785		},
30786
30787		stop : function () {
30788			this._clear();
30789
30790			D.unbind('.player');
30791
30792			this.isActive = false;
30793			this._timer   = this._speed = null;
30794
30795			F.trigger('onPlayEnd');
30796		},
30797
30798		toggle : function() {
30799			if (this.isActive) {
30800				this.stop();
30801
30802			} else {
30803				this.start.apply(this, arguments );
30804			}
30805		}
30806	};
30807
30808	/*
30809	 *	Overlay object
30810	 */
30811
30812	F.overlay = {
30813		el    : null,  // current handle
30814		theme : '',    // current theme
30815
30816		// Public methods
30817		open : function(opts) {
30818			var that  = this,
30819				el    = this.el,
30820				fixed = F.defaults.fixed,
30821				opacity,
30822				theme;
30823
30824			opts = $.extend({}, F.defaults.overlay, opts);
30825
30826			if (el) {
30827				el.stop(true).removeAttr('style').unbind('.overlay');
30828
30829			} else {
30830				el = $('<div class="fancybox-overlay' + (fixed ? ' fancybox-overlay-fixed' : '' ) + '"></div>').appendTo( opts.parent || 'body' );
30831			}
30832
30833			if (opts.closeClick) {
30834				el.bind('click.overlay', function(e) {
30835					// fix Android touch event bubbling issue
30836					if (F.lastTouch && (getTime() - F.lastTouch) < 300) {
30837						return false;
30838					}
30839
30840					if (F.isActive) {
30841						F.close();
30842					} else {
30843						that.close();
30844					}
30845
30846					return false;
30847				});
30848			}
30849
30850			theme = opts.theme || (F.coming ? F.coming.theme : 'default');
30851
30852			if (theme !== this.theme) {
30853				el.removeClass('fancybox-' + this.theme + '-overlay')
30854			}
30855
30856			this.theme = theme;
30857
30858			el.addClass('fancybox-' + theme + '-overlay').css( opts.css );
30859
30860			opacity = el.css('opacity');
30861
30862			if (!this.el && opacity < 1 && opts.speedIn) {
30863				el.css({
30864					opacity : 0,
30865					filter  : 'alpha(opacity=0)'  // This fixes IE flickering
30866				})
30867				.fadeTo( opts.speedIn, opacity );
30868			}
30869
30870			this.el = el;
30871
30872			if (!fixed) {
30873				W.bind('resize.overlay', $.proxy( this.update, this) );
30874
30875				this.update();
30876			}
30877		},
30878
30879		close : function(opts, callback) {
30880			opts = $.extend({}, F.defaults.overlay, opts);
30881
30882			if (this.el) {
30883				this.el.stop(true).fadeOut(opts.speedOut, function() {
30884					W.unbind('resize.overlay');
30885
30886					$('.fancybox-overlay').remove();
30887
30888					F.overlay.el = null;
30889
30890					if ($.isFunction(callback)) {
30891						callback();
30892					}
30893				});
30894			}
30895		},
30896
30897		update : function () {
30898			// Reset width/height so it will not mess
30899			this.el.css({width: '100%', height: '100%'});
30900
30901			this.el.width(D.width()).height(D.height());
30902		}
30903	};
30904
30905	/*
30906	 *	Touch object - adds swipe left/right events
30907	 */
30908
30909	F.touch = {
30910		startX   : 0,
30911		wrapX    : 0,
30912		dx       : 0,
30913		isMoving : false,
30914
30915		_start : function(e) {
30916			var current = F.current,
30917				data    = e.originalEvent.touches ? e.originalEvent.touches[0] : e,
30918				now     = getTime();
30919
30920			if (!F.isOpen || F.wrap.is(':animated')  || !( $(e.target).is(F.inner) || $(e.target).parent().is(F.inner) )) {
30921				return;
30922			}
30923
30924			if (F.lastTouch && (now - F.lastTouch) < 300) {
30925				e.preventDefault();
30926
30927				F.lastTouch = now;
30928
30929				this._cancel(true);
30930
30931				F.toggle();
30932
30933				return false;
30934			}
30935
30936			F.lastTouch = now;
30937
30938			if (F.wrap &&  F.wrap.outerWidth() > F.getViewport().w) {
30939				return;
30940			}
30941
30942			e.preventDefault();
30943
30944			if (data && F.wrap &&  F.wrap.outerWidth() < F.getViewport().w) {
30945				this.startX   = data.pageX;
30946				this.wrapX    = F.wrap.position().left;
30947				this.isMoving = true;
30948
30949				F.inner
30950					.bind('touchmove.fb', $.proxy(this._move, this) )
30951					.one("touchend.fb touchcancel.fb", $.proxy(this._cancel, this) );
30952			}
30953		},
30954
30955		_move : function(e) {
30956			var data = e.originalEvent.touches ? e.originalEvent.touches[0] : e,
30957				dx   = this.startX - data.pageX;
30958
30959			if (!this.isMoving || !F.isOpen) {
30960				return;
30961			}
30962
30963			this.dx = dx;
30964
30965			if (F.current.wrap.outerWidth(true) <= W.width()) {
30966
30967				if (Math.abs(dx) >= 50) {
30968					e.preventDefault();
30969
30970					this.last = 0;
30971
30972					this._cancel(true);
30973
30974					if (dx > 0) {
30975						F.next('left');
30976
30977					} else {
30978						F.prev('right');
30979					}
30980
30981				} else if (Math.abs(dx) > 3) {
30982					e.preventDefault();
30983
30984					this.last = 0;
30985
30986					F.wrap.css('left', this.wrapX - dx);
30987				}
30988			}
30989		},
30990
30991		_clear : function() {
30992			this.startX   = this.wrapX = this.dx = 0;
30993			this.isMoving = false;
30994		},
30995
30996		_cancel : function( stop ) {
30997			if (F.inner) {
30998				F.inner.unbind('touchmove.fb');
30999			}
31000
31001			if (F.isOpen && Math.abs(this.dx) > 3) {
31002				F.reposition(false);
31003			}
31004
31005			this._clear();
31006		},
31007
31008		init : function() {
31009			var that = this;
31010
31011			if (F.inner && F.touch) {
31012				this._cancel(true);
31013
31014				F.inner.bind('touchstart.fb', $.proxy(this._start, this));
31015			}
31016		}
31017	};
31018
31019	/*
31020	 *	Add default easing
31021	 */
31022
31023	if (!$.easing.easeOutQuad) {
31024		$.easing.easeOutQuad = function (x, t, b, c, d) {
31025			return -c *(t/=d)*(t-2) + b;
31026		};
31027	}
31028
31029	/*
31030	 *
31031	 */
31032
31033	D.ready(function() {
31034		var w1, w2, scrollV, scrollH;
31035
31036		// Tests that need a body at doc ready
31037		if ( $.scrollbarWidth === undefined ) {
31038			$.scrollbarWidth = function() {
31039				var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'),
31040					child  = parent.children(),
31041					width  = child.innerWidth() - child.height( 99 ).innerWidth();
31042
31043				parent.remove();
31044
31045				return width;
31046			};
31047		}
31048
31049		if ( $.support.fixedPosition === undefined ) {
31050			$.support.fixedPosition = (function() {
31051				var elem  = $('<div style="position:fixed;top:20px;padding:0;margin:0;border:0;"></div>').appendTo('body'),
31052					fixed = elem.css( 'position' ) === 'fixed' && ((elem[0].offsetTop > 18 && elem[0].offsetTop < 22) || elem[0].offsetTop === 15 );
31053
31054				elem.remove();
31055
31056				return fixed;
31057			}());
31058		}
31059
31060		$.extend(F.defaults, {
31061			scrollbarWidth : $.scrollbarWidth(),
31062			fixed  : $.support.fixedPosition,
31063			parent : $('body')
31064		});
31065
31066		// Quick and dirty code to get page scroll-bar width and create CSS style
31067		// Workaround for FF jumping bug
31068		scrollV = W.scrollTop();
31069		scrollH = W.scrollLeft();
31070
31071		w1 = $(window).width();
31072
31073		H.addClass('fancybox-lock-test');
31074
31075		w2 = $(window).width();
31076
31077		H.removeClass('fancybox-lock-test');
31078
31079		W.scrollTop( scrollV ).scrollLeft( scrollH );
31080
31081		F.lockMargin = (w2 - w1);
31082
31083		$("<style type='text/css'>.fancybox-margin{margin-right:" + F.lockMargin + "px;}</style>").appendTo("head");
31084
31085		// Auto start
31086		if ($("script[src*='magic.js']").attr('src').match(/autorun/)) {
31087			$("a[href$='.jpg'],a[href$='.png'],a[href$='.gif'],.fancybox").attr('data-fancybox-group', 'gallery').fancybox();
31088		}
31089	});
31090
31091	// jQuery plugin initialization
31092	$.fn.fancybox = function (options) {
31093		var that     = this,
31094			selector = this.length ? this.selector : false,
31095			live     = (selector && selector.indexOf('()') < 0 && !(options && options.live === false));
31096
31097		var handler  = function(e) {
31098			var collection = live ? $(selector) : that,
31099				group  = $(this).blur(),
31100				param  = options.groupAttr || 'data-fancybox-group',
31101				value  = group.attr( param ),
31102				tmp    = this.rel;
31103
31104			if (!value && tmp && tmp !== 'nofollow') {
31105				param = 'rel';
31106				value = tmp;
31107			}
31108
31109			if (value) {
31110				group = collection.filter('[' + param + '="' + value + '"]');
31111
31112				options.index = group.index( this );
31113			}
31114
31115			if (group.length) {
31116				e.preventDefault();
31117
31118				F.open(group.get(), options);
31119			}
31120		};
31121
31122		options = options || {};
31123
31124		if (live) {
31125			D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-close,.fancybox-nav,.fancybox-wrap')", 'click.fb-start', handler);
31126
31127		} else {
31128			that.unbind('click.fb-start').bind('click.fb-start', handler);
31129		}
31130
31131		return this;
31132	};
31133
31134}(window, document, jQuery));
31135/*
31136     _ _      _       _
31137 ___| (_) ___| | __  (_)___
31138/ __| | |/ __| |/ /  | / __|
31139\__ \ | | (__|   < _ | \__ \
31140|___/_|_|\___|_|\_(_)/ |___/
31141                   |__/
31142
31143 Version: 1.5.8
31144  Author: Ken Wheeler
31145 Website: http://kenwheeler.github.io
31146    Docs: http://kenwheeler.github.io/slick
31147    Repo: http://github.com/kenwheeler/slick
31148  Issues: http://github.com/kenwheeler/slick/issues
31149
31150 */
31151/* global window, document, define, jQuery, setInterval, clearInterval */
31152(function(factory) {
31153    'use strict';
31154    if (typeof define === 'function' && define.amd) {
31155        define(['jquery'], factory);
31156    } else if (typeof exports !== 'undefined') {
31157        module.exports = factory(require('jquery'));
31158    } else {
31159        factory(jQuery);
31160    }
31161
31162}(function($) {
31163    'use strict';
31164    var Slick = window.Slick || {};
31165
31166    Slick = (function() {
31167
31168        var instanceUid = 0;
31169
31170        function Slick(element, settings) {
31171
31172            var _ = this, dataSettings;
31173
31174            _.defaults = {
31175                accessibility: true,
31176                adaptiveHeight: false,
31177                appendArrows: $(element),
31178                appendDots: $(element),
31179                arrows: true,
31180                asNavFor: null,
31181                prevArrow: '<button type="button" data-role="none" class="slick-prev" aria-label="Previous" tabindex="0" role="button">Previous</button>',
31182                nextArrow: '<button type="button" data-role="none" class="slick-next" aria-label="Next" tabindex="0" role="button">Next</button>',
31183                autoplay: false,
31184                autoplaySpeed: 3000,
31185                centerMode: false,
31186                centerPadding: '50px',
31187                cssEase: 'ease',
31188                customPaging: function(slider, i) {
31189                    return '<button type="button" data-role="none" role="button" aria-required="false" tabindex="0">' + (i + 1) + '</button>';
31190                },
31191                dots: false,
31192                dotsClass: 'slick-dots',
31193                draggable: true,
31194                easing: 'linear',
31195                edgeFriction: 0.35,
31196                fade: false,
31197                focusOnSelect: false,
31198                infinite: true,
31199                initialSlide: 0,
31200                lazyLoad: 'ondemand',
31201                mobileFirst: false,
31202                pauseOnHover: true,
31203                pauseOnDotsHover: false,
31204                respondTo: 'window',
31205                responsive: null,
31206                rows: 1,
31207                rtl: false,
31208                slide: '',
31209                slidesPerRow: 1,
31210                slidesToShow: 1,
31211                slidesToScroll: 1,
31212                speed: 500,
31213                swipe: true,
31214                swipeToSlide: false,
31215                touchMove: true,
31216                touchThreshold: 5,
31217                useCSS: true,
31218                useTransform: false,
31219                variableWidth: false,
31220                vertical: false,
31221                verticalSwiping: false,
31222                waitForAnimate: true,
31223                zIndex: 1000
31224            };
31225
31226            _.initials = {
31227                animating: false,
31228                dragging: false,
31229                autoPlayTimer: null,
31230                currentDirection: 0,
31231                currentLeft: null,
31232                currentSlide: 0,
31233                direction: 1,
31234                $dots: null,
31235                listWidth: null,
31236                listHeight: null,
31237                loadIndex: 0,
31238                $nextArrow: null,
31239                $prevArrow: null,
31240                slideCount: null,
31241                slideWidth: null,
31242                $slideTrack: null,
31243                $slides: null,
31244                sliding: false,
31245                slideOffset: 0,
31246                swipeLeft: null,
31247                $list: null,
31248                touchObject: {},
31249                transformsEnabled: false,
vendor: 6,056 bytes, lines 31250-31430
31250                unslicked: false
31251            };
31252
31253            $.extend(_, _.initials);
31254
31255            _.activeBreakpoint = null;
31256            _.animType = null;
31257            _.animProp = null;
31258            _.breakpoints = [];
31259            _.breakpointSettings = [];
31260            _.cssTransitions = false;
31261            _.hidden = 'hidden';
31262            _.paused = false;
31263            _.positionProp = null;
31264            _.respondTo = null;
31265            _.rowCount = 1;
31266            _.shouldClick = true;
31267            _.$slider = $(element);
31268            _.$slidesCache = null;
31269            _.transformType = null;
31270            _.transitionType = null;
31271            _.visibilityChange = 'visibilitychange';
31272            _.windowWidth = 0;
31273            _.windowTimer = null;
31274
31275            dataSettings = $(element).data('slick') || {};
31276
31277            _.options = $.extend({}, _.defaults, dataSettings, settings);
31278
31279            _.currentSlide = _.options.initialSlide;
31280
31281            _.originalSettings = _.options;
31282
31283            if (typeof document.mozHidden !== 'undefined') {
31284                _.hidden = 'mozHidden';
31285                _.visibilityChange = 'mozvisibilitychange';
31286            } else if (typeof document.webkitHidden !== 'undefined') {
31287                _.hidden = 'webkitHidden';
31288                _.visibilityChange = 'webkitvisibilitychange';
31289            }
31290
31291            _.autoPlay = $.proxy(_.autoPlay, _);
31292            _.autoPlayClear = $.proxy(_.autoPlayClear, _);
31293            _.changeSlide = $.proxy(_.changeSlide, _);
31294            _.clickHandler = $.proxy(_.clickHandler, _);
31295            _.selectHandler = $.proxy(_.selectHandler, _);
31296            _.setPosition = $.proxy(_.setPosition, _);
31297            _.swipeHandler = $.proxy(_.swipeHandler, _);
31298            _.dragHandler = $.proxy(_.dragHandler, _);
31299            _.keyHandler = $.proxy(_.keyHandler, _);
31300            _.autoPlayIterator = $.proxy(_.autoPlayIterator, _);
31301
31302            _.instanceUid = instanceUid++;
31303
31304            // A simple way to check for HTML strings
31305            // Strict HTML recognition (must start with <)
31306            // Extracted from jQuery v1.11 source
31307            _.htmlExpr = /^(?:\s*(<[\w\W]+>)[^>]*)$/;
31308
31309
31310            _.registerBreakpoints();
31311            _.init(true);
31312            _.checkResponsive(true);
31313
31314        }
31315
31316        return Slick;
31317
31318    }());
31319
31320    Slick.prototype.addSlide = Slick.prototype.slickAdd = function(markup, index, addBefore) {
31321
31322        var _ = this;
31323
31324        if (typeof(index) === 'boolean') {
31325            addBefore = index;
31326            index = null;
31327        } else if (index < 0 || (index >= _.slideCount)) {
31328            return false;
31329        }
31330
31331        _.unload();
31332
31333        if (typeof(index) === 'number') {
31334            if (index === 0 && _.$slides.length === 0) {
31335                $(markup).appendTo(_.$slideTrack);
31336            } else if (addBefore) {
31337                $(markup).insertBefore(_.$slides.eq(index));
31338            } else {
31339                $(markup).insertAfter(_.$slides.eq(index));
31340            }
31341        } else {
31342            if (addBefore === true) {
31343                $(markup).prependTo(_.$slideTrack);
31344            } else {
31345                $(markup).appendTo(_.$slideTrack);
31346            }
31347        }
31348
31349        _.$slides = _.$slideTrack.children(this.options.slide);
31350
31351        _.$slideTrack.children(this.options.slide).detach();
31352
31353        _.$slideTrack.append(_.$slides);
31354
31355        _.$slides.each(function(index, element) {
31356            $(element).attr('data-slick-index', index);
31357        });
31358
31359        _.$slidesCache = _.$slides;
31360
31361        _.reinit();
31362
31363    };
31364
31365    Slick.prototype.animateHeight = function() {
31366        var _ = this;
31367        if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {
31368            var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);
31369            _.$list.animate({
31370                height: targetHeight
31371            }, _.options.speed);
31372        }
31373    };
31374
31375    Slick.prototype.animateSlide = function(targetLeft, callback) {
31376
31377        var animProps = {},
31378            _ = this;
31379
31380        _.animateHeight();
31381
31382        if (_.options.rtl === true && _.options.vertical === false) {
31383            targetLeft = -targetLeft;
31384        }
31385        if (_.transformsEnabled === false) {
31386            if (_.options.vertical === false) {
31387                _.$slideTrack.animate({
31388                    left: targetLeft
31389                }, _.options.speed, _.options.easing, callback);
31390            } else {
31391                _.$slideTrack.animate({
31392                    top: targetLeft
31393                }, _.options.speed, _.options.easing, callback);
31394            }
31395
31396        } else {
31397
31398            if (_.cssTransitions === false) {
31399                if (_.options.rtl === true) {
31400                    _.currentLeft = -(_.currentLeft);
31401                }
31402                $({
31403                    animStart: _.currentLeft
31404                }).animate({
31405                    animStart: targetLeft
31406                }, {
31407                    duration: _.options.speed,
31408                    easing: _.options.easing,
31409                    step: function(now) {
31410                        now = Math.ceil(now);
31411                        if (_.options.vertical === false) {
31412                            animProps[_.animType] = 'translate(' +
31413                                now + 'px, 0px)';
31414                            _.$slideTrack.css(animProps);
31415                        } else {
31416                            animProps[_.animType] = 'translate(0px,' +
31417                                now + 'px)';
31418                            _.$slideTrack.css(animProps);
31419                        }
31420                    },
31421                    complete: function() {
31422                        if (callback) {
31423                            callback.call();
31424                        }
31425                    }
31426                });
31427
31428            } else {
31429
31430                _.applyTransition();
31431                targetLeft = Math.ceil(targetLeft);
31432
31433                if (_.options.vertical === false) {
31434                    animProps[_.animType] = 'translate3d(' + targetLeft + 'px, 0px, 0px)';
31435                } else {
31436                    animProps[_.animType] = 'translate3d(0px,' + targetLeft + 'px, 0px)';
31437                }
31438                _.$slideTrack.css(animProps);
31439
31440                if (callback) {
31441                    setTimeout(function() {
31442
31443                        _.disableTransition();
31444
31445                        callback.call();
31446                    }, _.options.speed);
31447                }
31448
31449            }
31450
31451        }
31452
31453    };
31454
31455    Slick.prototype.asNavFor = function(index) {
31456
31457        var _ = this,
31458            asNavFor = _.options.asNavFor;
31459
31460        if ( asNavFor && asNavFor !== null ) {
31461            asNavFor = $(asNavFor).not(_.$slider);
31462        }
31463
31464        if ( asNavFor !== null && typeof asNavFor === 'object' ) {
31465            asNavFor.each(function() {
31466                var target = $(this).slick('getSlick');
31467                if(!target.unslicked) {
31468                    target.slideHandler(index, true);
31469                }
31470            });
31471        }
31472
31473    };
31474
31475    Slick.prototype.applyTransition = function(slide) {
31476
31477        var _ = this,
31478            transition = {};
31479
31480        if (_.options.fade === false) {
31481            transition[_.transitionType] = _.transformType + ' ' + _.options.speed + 'ms ' + _.options.cssEase;
31482        } else {
31483            transition[_.transitionType] = 'opacity ' + _.options.speed + 'ms ' + _.options.cssEase;
31484        }
31485
31486        if (_.options.fade === false) {
31487            _.$slideTrack.css(transition);
31488        } else {
31489            _.$slides.eq(slide).css(transition);
31490        }
31491
31492    };
31493
31494    Slick.prototype.autoPlay = function() {
31495
31496        var _ = this;
31497
31498        if (_.autoPlayTimer) {
31499            clearInterval(_.autoPlayTimer);
31500        }
31501
31502        if (_.slideCount > _.options.slidesToShow && _.paused !== true) {
31503            _.autoPlayTimer = setInterval(_.autoPlayIterator,
31504                _.options.autoplaySpeed);
31505        }
31506
31507    };
31508
31509    Slick.prototype.autoPlayClear = function() {
31510
31511        var _ = this;
31512        if (_.autoPlayTimer) {
31513            clearInterval(_.autoPlayTimer);
31514        }
31515
31516    };
31517
31518    Slick.prototype.autoPlayIterator = function() {
31519
31520        var _ = this;
31521
31522        if (_.options.infinite === false) {
31523
31524            if (_.direction === 1) {
31525
31526                if ((_.currentSlide + 1) === _.slideCount -
31527                    1) {
31528                    _.direction = 0;
31529                }
31530
31531                _.slideHandler(_.currentSlide + _.options.slidesToScroll);
31532
31533            } else {
31534
31535                if ((_.currentSlide - 1 === 0)) {
31536
31537                    _.direction = 1;
31538
31539                }
31540
31541                _.slideHandler(_.currentSlide - _.options.slidesToScroll);
31542
31543            }
31544
31545        } else {
31546
31547            _.slideHandler(_.currentSlide + _.options.slidesToScroll);
31548
31549        }
31550
31551    };
31552
31553    Slick.prototype.buildArrows = function() {
31554
31555        var _ = this;
31556
31557        if (_.options.arrows === true ) {
31558
31559            _.$prevArrow = $(_.options.prevArrow).addClass('slick-arrow');
31560            _.$nextArrow = $(_.options.nextArrow).addClass('slick-arrow');
31561
31562            if( _.slideCount > _.options.slidesToShow ) {
31563
31564                _.$prevArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex');
31565                _.$nextArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex');
31566
31567                if (_.htmlExpr.test(_.options.prevArrow)) {
31568                    _.$prevArrow.prependTo(_.options.appendArrows);
31569                }
31570
31571                if (_.htmlExpr.test(_.options.nextArrow)) {
31572                    _.$nextArrow.appendTo(_.options.appendArrows);
31573                }
31574
31575                if (_.options.infinite !== true) {
31576                    _.$prevArrow
31577                        .addClass('slick-disabled')
31578                        .attr('aria-disabled', 'true');
31579                }
31580
31581            } else {
31582
31583                _.$prevArrow.add( _.$nextArrow )
31584
31585                    .addClass('slick-hidden')
31586                    .attr({
31587                        'aria-disabled': 'true',
31588                        'tabindex': '-1'
31589                    });
31590
31591            }
31592
31593        }
31594
31595    };
31596
31597    Slick.prototype.buildDots = function() {
31598
31599        var _ = this,
31600            i, dotString;
31601
31602        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
31603
31604            dotString = '<ul class="' + _.options.dotsClass + '">';
31605
31606            for (i = 0; i <= _.getDotCount(); i += 1) {
31607                dotString += '<li>' + _.options.customPaging.call(this, _, i) + '</li>';
31608            }
31609
31610            dotString += '</ul>';
31611
31612            _.$dots = $(dotString).appendTo(
vendor: 9,145 bytes, lines 31613-31865
31613                _.options.appendDots);
31614
31615            _.$dots.find('li').first().addClass('slick-active').attr('aria-hidden', 'false');
31616
31617        }
31618
31619    };
31620
31621    Slick.prototype.buildOut = function() {
31622
31623        var _ = this;
31624
31625        _.$slides =
31626            _.$slider
31627                .children( _.options.slide + ':not(.slick-cloned)')
31628                .addClass('slick-slide');
31629
31630        _.slideCount = _.$slides.length;
31631
31632        _.$slides.each(function(index, element) {
31633            $(element)
31634                .attr('data-slick-index', index)
31635                .data('originalStyling', $(element).attr('style') || '');
31636        });
31637
31638        _.$slidesCache = _.$slides;
31639
31640        _.$slider.addClass('slick-slider');
31641
31642        _.$slideTrack = (_.slideCount === 0) ?
31643            $('<div class="slick-track"/>').appendTo(_.$slider) :
31644            _.$slides.wrapAll('<div class="slick-track"/>').parent();
31645
31646        _.$list = _.$slideTrack.wrap(
31647            '<div aria-live="polite" class="slick-list"/>').parent();
31648        _.$slideTrack.css('opacity', 0);
31649
31650        if (_.options.centerMode === true || _.options.swipeToSlide === true) {
31651            _.options.slidesToScroll = 1;
31652        }
31653
31654        $('img[data-lazy]', _.$slider).not('[src]').addClass('slick-loading');
31655
31656        _.setupInfinite();
31657
31658        _.buildArrows();
31659
31660        _.buildDots();
31661
31662        _.updateDots();
31663
31664
31665        _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0);
31666
31667        if (_.options.draggable === true) {
31668            _.$list.addClass('draggable');
31669        }
31670
31671    };
31672
31673    Slick.prototype.buildRows = function() {
31674
31675        var _ = this, a, b, c, newSlides, numOfSlides, originalSlides,slidesPerSection;
31676
31677        newSlides = document.createDocumentFragment();
31678        originalSlides = _.$slider.children();
31679
31680        if(_.options.rows > 1) {
31681
31682            slidesPerSection = _.options.slidesPerRow * _.options.rows;
31683            numOfSlides = Math.ceil(
31684                originalSlides.length / slidesPerSection
31685            );
31686
31687            for(a = 0; a < numOfSlides; a++){
31688                var slide = document.createElement('div');
31689                for(b = 0; b < _.options.rows; b++) {
31690                    var row = document.createElement('div');
31691                    for(c = 0; c < _.options.slidesPerRow; c++) {
31692                        var target = (a * slidesPerSection + ((b * _.options.slidesPerRow) + c));
31693                        if (originalSlides.get(target)) {
31694                            row.appendChild(originalSlides.get(target));
31695                        }
31696                    }
31697                    slide.appendChild(row);
31698                }
31699                newSlides.appendChild(slide);
31700            }
31701
31702            _.$slider.html(newSlides);
31703            _.$slider.children().children().children()
31704                .css({
31705                    'width':(100 / _.options.slidesPerRow) + '%',
31706                    'display': 'inline-block'
31707                });
31708
31709        }
31710
31711    };
31712
31713    Slick.prototype.checkResponsive = function(initial, forceUpdate) {
31714
31715        var _ = this,
31716            breakpoint, targetBreakpoint, respondToWidth, triggerBreakpoint = false;
31717        var sliderWidth = _.$slider.width();
31718        var windowWidth = window.innerWidth || $(window).width();
31719
31720        if (_.respondTo === 'window') {
31721            respondToWidth = windowWidth;
31722        } else if (_.respondTo === 'slider') {
31723            respondToWidth = sliderWidth;
31724        } else if (_.respondTo === 'min') {
31725            respondToWidth = Math.min(windowWidth, sliderWidth);
31726        }
31727
31728        if ( _.options.responsive &&
31729            _.options.responsive.length &&
31730            _.options.responsive !== null) {
31731
31732            targetBreakpoint = null;
31733
31734            for (breakpoint in _.breakpoints) {
31735                if (_.breakpoints.hasOwnProperty(breakpoint)) {
31736                    if (_.originalSettings.mobileFirst === false) {
31737                        if (respondToWidth < _.breakpoints[breakpoint]) {
31738                            targetBreakpoint = _.breakpoints[breakpoint];
31739                        }
31740                    } else {
31741                        if (respondToWidth > _.breakpoints[breakpoint]) {
31742                            targetBreakpoint = _.breakpoints[breakpoint];
31743                        }
31744                    }
31745                }
31746            }
31747
31748            if (targetBreakpoint !== null) {
31749                if (_.activeBreakpoint !== null) {
31750                    if (targetBreakpoint !== _.activeBreakpoint || forceUpdate) {
31751                        _.activeBreakpoint =
31752                            targetBreakpoint;
31753                        if (_.breakpointSettings[targetBreakpoint] === 'unslick') {
31754                            _.unslick(targetBreakpoint);
31755                        } else {
31756                            _.options = $.extend({}, _.originalSettings,
31757                                _.breakpointSettings[
31758                                    targetBreakpoint]);
31759                            if (initial === true) {
31760                                _.currentSlide = _.options.initialSlide;
31761                            }
31762                            _.refresh(initial);
31763                        }
31764                        triggerBreakpoint = targetBreakpoint;
31765                    }
31766                } else {
31767                    _.activeBreakpoint = targetBreakpoint;
31768                    if (_.breakpointSettings[targetBreakpoint] === 'unslick') {
31769                        _.unslick(targetBreakpoint);
31770                    } else {
31771                        _.options = $.extend({}, _.originalSettings,
31772                            _.breakpointSettings[
31773                                targetBreakpoint]);
31774                        if (initial === true) {
31775                            _.currentSlide = _.options.initialSlide;
31776                        }
31777                        _.refresh(initial);
31778                    }
31779                    triggerBreakpoint = targetBreakpoint;
31780                }
31781            } else {
31782                if (_.activeBreakpoint !== null) {
31783                    _.activeBreakpoint = null;
31784                    _.options = _.originalSettings;
31785                    if (initial === true) {
31786                        _.currentSlide = _.options.initialSlide;
31787                    }
31788                    _.refresh(initial);
31789                    triggerBreakpoint = targetBreakpoint;
31790                }
31791            }
31792
31793            // only trigger breakpoints during an actual break. not on initialize.
31794            if( !initial && triggerBreakpoint !== false ) {
31795                _.$slider.trigger('breakpoint', [_, triggerBreakpoint]);
31796            }
31797        }
31798
31799    };
31800
31801    Slick.prototype.changeSlide = function(event, dontAnimate) {
31802
31803        var _ = this,
31804            $target = $(event.target),
31805            indexOffset, slideOffset, unevenOffset;
31806
31807        // If target is a link, prevent default action.
31808        if($target.is('a')) {
31809            event.preventDefault();
31810        }
31811
31812        // If target is not the <li> element (ie: a child), find the <li>.
31813        if(!$target.is('li')) {
31814            $target = $target.closest('li');
31815        }
31816
31817        unevenOffset = (_.slideCount % _.options.slidesToScroll !== 0);
31818        indexOffset = unevenOffset ? 0 : (_.slideCount - _.currentSlide) % _.options.slidesToScroll;
31819
31820        switch (event.data.message) {
31821
31822            case 'previous':
31823                slideOffset = indexOffset === 0 ? _.options.slidesToScroll : _.options.slidesToShow - indexOffset;
31824                if (_.slideCount > _.options.slidesToShow) {
31825                    _.slideHandler(_.currentSlide - slideOffset, false, dontAnimate);
31826                }
31827                break;
31828
31829            case 'next':
31830                slideOffset = indexOffset === 0 ? _.options.slidesToScroll : indexOffset;
31831                if (_.slideCount > _.options.slidesToShow) {
31832                    _.slideHandler(_.currentSlide + slideOffset, false, dontAnimate);
31833                }
31834                break;
31835
31836            case 'index':
31837                var index = event.data.index === 0 ? 0 :
31838                    event.data.index || $target.index() * _.options.slidesToScroll;
31839
31840                _.slideHandler(_.checkNavigable(index), false, dontAnimate);
31841                $target.children().trigger('focus');
31842                break;
31843
31844            default:
31845                return;
31846        }
31847
31848    };
31849
31850    Slick.prototype.checkNavigable = function(index) {
31851
31852        var _ = this,
31853            navigables, prevNavigable;
31854
31855        navigables = _.getNavigableIndexes();
31856        prevNavigable = 0;
31857        if (index > navigables[navigables.length - 1]) {
31858            index = navigables[navigables.length - 1];
31859        } else {
31860            for (var n in navigables) {
31861                if (index < navigables[n]) {
31862                    index = prevNavigable;
31863                    break;
31864                }
31865                prevNavigable = navigables[n];
31866            }
31867        }
31868
31869        return index;
31870    };
31871
31872    Slick.prototype.cleanUpEvents = function() {
31873
31874        var _ = this;
31875
31876        if (_.options.dots && _.$dots !== null) {
31877
31878            $('li', _.$dots).off('click.slick', _.changeSlide);
31879
31880            if (_.options.pauseOnDotsHover === true && _.options.autoplay === true) {
31881
31882                $('li', _.$dots)
31883                    .off('mouseenter.slick', $.proxy(_.setPaused, _, true))
31884                    .off('mouseleave.slick', $.proxy(_.setPaused, _, false));
31885
31886            }
31887
31888        }
31889
31890        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
31891            _.$prevArrow && _.$prevArrow.off('click.slick', _.changeSlide);
31892            _.$nextArrow && _.$nextArrow.off('click.slick', _.changeSlide);
31893        }
31894
31895        _.$list.off('touchstart.slick mousedown.slick', _.swipeHandler);
31896        _.$list.off('touchmove.slick mousemove.slick', _.swipeHandler);
31897        _.$list.off('touchend.slick mouseup.slick', _.swipeHandler);
vendor: 5,198 bytes, lines 31898-32098
31898        _.$list.off('touchcancel.slick mouseleave.slick', _.swipeHandler);
31899
31900        _.$list.off('click.slick', _.clickHandler);
31901
31902        $(document).off(_.visibilityChange, _.visibility);
31903
31904        _.$list.off('mouseenter.slick', $.proxy(_.setPaused, _, true));
31905        _.$list.off('mouseleave.slick', $.proxy(_.setPaused, _, false));
31906
31907        if (_.options.accessibility === true) {
31908            _.$list.off('keydown.slick', _.keyHandler);
31909        }
31910
31911        if (_.options.focusOnSelect === true) {
31912            $(_.$slideTrack).children().off('click.slick', _.selectHandler);
31913        }
31914
31915        $(window).off('orientationchange.slick.slick-' + _.instanceUid, _.orientationChange);
31916
31917        $(window).off('resize.slick.slick-' + _.instanceUid, _.resize);
31918
31919        $('[draggable!=true]', _.$slideTrack).off('dragstart', _.preventDefault);
31920
31921        $(window).off('load.slick.slick-' + _.instanceUid, _.setPosition);
31922        $(document).off('ready.slick.slick-' + _.instanceUid, _.setPosition);
31923    };
31924
31925    Slick.prototype.cleanUpRows = function() {
31926
31927        var _ = this, originalSlides;
31928
31929        if(_.options.rows > 1) {
31930            originalSlides = _.$slides.children().children();
31931            originalSlides.removeAttr('style');
31932            _.$slider.html(originalSlides);
31933        }
31934
31935    };
31936
31937    Slick.prototype.clickHandler = function(event) {
31938
31939        var _ = this;
31940
31941        if (_.shouldClick === false) {
31942            event.stopImmediatePropagation();
31943            event.stopPropagation();
31944            event.preventDefault();
31945        }
31946
31947    };
31948
31949    Slick.prototype.destroy = function(refresh) {
31950
31951        var _ = this;
31952
31953        _.autoPlayClear();
31954
31955        _.touchObject = {};
31956
31957        _.cleanUpEvents();
31958
31959        $('.slick-cloned', _.$slider).detach();
31960
31961        if (_.$dots) {
31962            _.$dots.remove();
31963        }
31964
31965
31966        if ( _.$prevArrow && _.$prevArrow.length ) {
31967
31968            _.$prevArrow
31969                .removeClass('slick-disabled slick-arrow slick-hidden')
31970                .removeAttr('aria-hidden aria-disabled tabindex')
31971                .css("display","");
31972
31973            if ( _.htmlExpr.test( _.options.prevArrow )) {
31974                _.$prevArrow.remove();
31975            }
31976        }
31977
31978        if ( _.$nextArrow && _.$nextArrow.length ) {
31979
31980            _.$nextArrow
31981                .removeClass('slick-disabled slick-arrow slick-hidden')
31982                .removeAttr('aria-hidden aria-disabled tabindex')
31983                .css("display","");
31984
31985            if ( _.htmlExpr.test( _.options.nextArrow )) {
31986                _.$nextArrow.remove();
31987            }
31988
31989        }
31990
31991
31992        if (_.$slides) {
31993
31994            _.$slides
31995                .removeClass('slick-slide slick-active slick-center slick-visible slick-current')
31996                .removeAttr('aria-hidden')
31997                .removeAttr('data-slick-index')
31998                .each(function(){
31999                    $(this).attr('style', $(this).data('originalStyling'));
32000                });
32001
32002            _.$slideTrack.children(this.options.slide).detach();
32003
32004            _.$slideTrack.detach();
32005
32006            _.$list.detach();
32007
32008            _.$slider.append(_.$slides);
32009        }
32010
32011        _.cleanUpRows();
32012
32013        _.$slider.removeClass('slick-slider');
32014        _.$slider.removeClass('slick-initialized');
32015
32016        _.unslicked = true;
32017
32018        if(!refresh) {
32019            _.$slider.trigger('destroy', [_]);
32020        }
32021
32022    };
32023
32024    Slick.prototype.disableTransition = function(slide) {
32025
32026        var _ = this,
32027            transition = {};
32028
32029        transition[_.transitionType] = '';
32030
32031        if (_.options.fade === false) {
32032            _.$slideTrack.css(transition);
32033        } else {
32034            _.$slides.eq(slide).css(transition);
32035        }
32036
32037    };
32038
32039    Slick.prototype.fadeSlide = function(slideIndex, callback) {
32040
32041        var _ = this;
32042
32043        if (_.cssTransitions === false) {
32044
32045            _.$slides.eq(slideIndex).css({
32046                zIndex: _.options.zIndex
32047            });
32048
32049            _.$slides.eq(slideIndex).animate({
32050                opacity: 1
32051            }, _.options.speed, _.options.easing, callback);
32052
32053        } else {
32054
32055            _.applyTransition(slideIndex);
32056
32057            _.$slides.eq(slideIndex).css({
32058                opacity: 1,
32059                zIndex: _.options.zIndex
32060            });
32061
32062            if (callback) {
32063                setTimeout(function() {
32064
32065                    _.disableTransition(slideIndex);
32066
32067                    callback.call();
32068                }, _.options.speed);
32069            }
32070
32071        }
32072
32073    };
32074
32075    Slick.prototype.fadeSlideOut = function(slideIndex) {
32076
32077        var _ = this;
32078
32079        if (_.cssTransitions === false) {
32080
32081            _.$slides.eq(slideIndex).animate({
32082                opacity: 0,
32083                zIndex: _.options.zIndex - 2
32084            }, _.options.speed, _.options.easing);
32085
32086        } else {
32087
32088            _.applyTransition(slideIndex);
32089
32090            _.$slides.eq(slideIndex).css({
32091                opacity: 0,
32092                zIndex: _.options.zIndex - 2
32093            });
32094
32095        }
32096
32097    };
32098
32099    Slick.prototype.filterSlides = Slick.prototype.slickFilter = function(filter) {
32100
32101        var _ = this;
32102
32103        if (filter !== null) {
32104
32105            _.unload();
32106
32107            _.$slideTrack.children(this.options.slide).detach();
32108
32109            _.$slidesCache.filter(filter).appendTo(_.$slideTrack);
32110
32111            _.reinit();
32112
32113        }
32114
32115    };
32116
32117    Slick.prototype.getCurrent = Slick.prototype.slickCurrentSlide = function() {
32118
32119        var _ = this;
32120        return _.currentSlide;
32121
32122    };
32123
32124    Slick.prototype.getDotCount = function() {
32125
32126        var _ = this;
32127
32128        var breakPoint = 0;
32129        var counter = 0;
32130        var pagerQty = 0;
32131
32132        if (_.options.infinite === true) {
32133            while (breakPoint < _.slideCount) {
32134                ++pagerQty;
32135                breakPoint = counter + _.options.slidesToShow;
32136                counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
32137            }
32138        } else if (_.options.centerMode === true) {
32139            pagerQty = _.slideCount;
32140        } else {
32141            while (breakPoint < _.slideCount) {
32142                ++pagerQty;
32143                breakPoint = counter + _.options.slidesToShow;
32144                counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
32145            }
32146        }
32147
32148        return pagerQty - 1;
32149
32150    };
32151
32152    Slick.prototype.getLeft = function(slideIndex) {
32153
32154        var _ = this,
32155            targetLeft,
32156            verticalHeight,
32157            verticalOffset = 0,
32158            targetSlide;
32159
32160        _.slideOffset = 0;
32161        verticalHeight = _.$slides.first().outerHeight(true);
32162
32163        if (_.options.infinite === true) {
32164            if (_.slideCount > _.options.slidesToShow) {
32165                _.slideOffset = (_.slideWidth * _.options.slidesToShow) * -1;
32166                verticalOffset = (verticalHeight * _.options.slidesToShow) * -1;
32167            }
32168            if (_.slideCount % _.options.slidesToScroll !== 0) {
32169                if (slideIndex + _.options.slidesToScroll > _.slideCount && _.slideCount > _.options.slidesToShow) {
32170                    if (slideIndex > _.slideCount) {
32171                        _.slideOffset = ((_.options.slidesToShow - (sl
vendor: 10,685 bytes, lines 32171-32501
32171ideIndex - _.slideCount)) * _.slideWidth) * -1;
32172                        verticalOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * verticalHeight) * -1;
32173                    } else {
32174                        _.slideOffset = ((_.slideCount % _.options.slidesToScroll) * _.slideWidth) * -1;
32175                        verticalOffset = ((_.slideCount % _.options.slidesToScroll) * verticalHeight) * -1;
32176                    }
32177                }
32178            }
32179        } else {
32180            if (slideIndex + _.options.slidesToShow > _.slideCount) {
32181                _.slideOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * _.slideWidth;
32182                verticalOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * verticalHeight;
32183            }
32184        }
32185
32186        if (_.slideCount <= _.options.slidesToShow) {
32187            _.slideOffset = 0;
32188            verticalOffset = 0;
32189        }
32190
32191        if (_.options.centerMode === true && _.options.infinite === true) {
32192            _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2) - _.slideWidth;
32193        } else if (_.options.centerMode === true) {
32194            _.slideOffset = 0;
32195            _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2);
32196        }
32197
32198        if (_.options.vertical === false) {
32199            targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
32200        } else {
32201            targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset;
32202        }
32203
32204        if (_.options.variableWidth === true) {
32205
32206            if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) {
32207                targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex);
32208            } else {
32209                targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow);
32210            }
32211
32212            targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0;
32213
32214            if (_.options.centerMode === true) {
32215                if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) {
32216                    targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex);
32217                } else {
32218                    targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow + 1);
32219                }
32220                targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0;
32221                targetLeft += (_.$list.width() - targetSlide.outerWidth()) / 2;
32222            }
32223        }
32224
32225        return targetLeft;
32226
32227    };
32228
32229    Slick.prototype.getOption = Slick.prototype.slickGetOption = function(option) {
32230
32231        var _ = this;
32232
32233        return _.options[option];
32234
32235    };
32236
32237    Slick.prototype.getNavigableIndexes = function() {
32238
32239        var _ = this,
32240            breakPoint = 0,
32241            counter = 0,
32242            indexes = [],
32243            max;
32244
32245        if (_.options.infinite === false) {
32246            max = _.slideCount;
32247        } else {
32248            breakPoint = _.options.slidesToScroll * -1;
32249            counter = _.options.slidesToScroll * -1;
32250            max = _.slideCount * 2;
32251        }
32252
32253        while (breakPoint < max) {
32254            indexes.push(breakPoint);
32255            breakPoint = counter + _.options.slidesToScroll;
32256            counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
32257        }
32258
32259        return indexes;
32260
32261    };
32262
32263    Slick.prototype.getSlick = function() {
32264
32265        return this;
32266
32267    };
32268
32269    Slick.prototype.getSlideCount = function() {
32270
32271        var _ = this,
32272            slidesTraversed, swipedSlide, centerOffset;
32273
32274        centerOffset = _.options.centerMode === true ? _.slideWidth * Math.floor(_.options.slidesToShow / 2) : 0;
32275
32276        if (_.options.swipeToSlide === true) {
32277            _.$slideTrack.find('.slick-slide').each(function(index, slide) {
32278                if (slide.offsetLeft - centerOffset + ($(slide).outerWidth() / 2) > (_.swipeLeft * -1)) {
32279                    swipedSlide = slide;
32280                    return false;
32281                }
32282            });
32283
32284            slidesTraversed = Math.abs($(swipedSlide).attr('data-slick-index') - _.currentSlide) || 1;
32285
32286            return slidesTraversed;
32287
32288        } else {
32289            return _.options.slidesToScroll;
32290        }
32291
32292    };
32293
32294    Slick.prototype.goTo = Slick.prototype.slickGoTo = function(slide, dontAnimate) {
32295
32296        var _ = this;
32297
32298        _.changeSlide({
32299            data: {
32300                message: 'index',
32301                index: parseInt(slide)
32302            }
32303        }, dontAnimate);
32304
32305    };
32306
32307    Slick.prototype.init = function(creation) {
32308
32309        var _ = this;
32310
32311        if (!$(_.$slider).hasClass('slick-initialized')) {
32312
32313            $(_.$slider).addClass('slick-initialized');
32314
32315            _.buildRows();
32316            _.buildOut();
32317            _.setProps();
32318            _.startLoad();
32319            _.loadSlider();
32320            _.initializeEvents();
32321            _.updateArrows();
32322            _.updateDots();
32323
32324        }
32325
32326        if (creation) {
32327            _.$slider.trigger('init', [_]);
32328        }
32329
32330        if (_.options.accessibility === true) {
32331            _.initADA();
32332        }
32333
32334    };
32335
32336    Slick.prototype.initArrowEvents = function() {
32337
32338        var _ = this;
32339
32340        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
32341            _.$prevArrow.on('click.slick', {
32342                message: 'previous'
32343            }, _.changeSlide);
32344            _.$nextArrow.on('click.slick', {
32345                message: 'next'
32346            }, _.changeSlide);
32347        }
32348
32349    };
32350
32351    Slick.prototype.initDotEvents = function() {
32352
32353        var _ = this;
32354
32355        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
32356            $('li', _.$dots).on('click.slick', {
32357                message: 'index'
32358            }, _.changeSlide);
32359        }
32360
32361        if (_.options.dots === true && _.options.pauseOnDotsHover === true && _.options.autoplay === true) {
32362            $('li', _.$dots)
32363                .on('mouseenter.slick', $.proxy(_.setPaused, _, true))
32364                .on('mouseleave.slick', $.proxy(_.setPaused, _, false));
32365        }
32366
32367    };
32368
32369    Slick.prototype.initializeEvents = function() {
32370
32371        var _ = this;
32372
32373        _.initArrowEvents();
32374
32375        _.initDotEvents();
32376
32377        _.$list.on('touchstart.slick mousedown.slick', {
32378            action: 'start'
32379        }, _.swipeHandler);
32380        _.$list.on('touchmove.slick mousemove.slick', {
32381            action: 'move'
32382        }, _.swipeHandler);
32383        _.$list.on('touchend.slick mouseup.slick', {
32384            action: 'end'
32385        }, _.swipeHandler);
32386        _.$list.on('touchcancel.slick mouseleave.slick', {
32387            action: 'end'
32388        }, _.swipeHandler);
32389
32390        _.$list.on('click.slick', _.clickHandler);
32391
32392        $(document).on(_.visibilityChange, $.proxy(_.visibility, _));
32393
32394        _.$list.on('mouseenter.slick', $.proxy(_.setPaused, _, true));
32395        _.$list.on('mouseleave.slick', $.proxy(_.setPaused, _, false));
32396
32397        if (_.options.accessibility === true) {
32398            _.$list.on('keydown.slick', _.keyHandler);
32399        }
32400
32401        if (_.options.focusOnSelect === true) {
32402            $(_.$slideTrack).children().on('click.slick', _.selectHandler);
32403        }
32404
32405        $(window).on('orientationchange.slick.slick-' + _.instanceUid, $.proxy(_.orientationChange, _));
32406
32407        $(window).on('resize.slick.slick-' + _.instanceUid, $.proxy(_.resize, _));
32408
32409        $('[draggable!=true]', _.$slideTrack).on('dragstart', _.preventDefault);
32410
32411        $(window).on('load.slick.slick-' + _.instanceUid, _.setPosition);
32412        $(document).on('ready.slick.slick-' + _.instanceUid, _.setPosition);
32413
32414    };
32415
32416    Slick.prototype.initUI = function() {
32417
32418        var _ = this;
32419
32420        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
32421
32422            _.$prevArrow.show();
32423            _.$nextArrow.show();
32424
32425        }
32426
32427        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
32428
32429            _.$dots.show();
32430
32431        }
32432
32433        if (_.options.autoplay === true) {
32434
32435            _.autoPlay();
32436
32437        }
32438
32439    };
32440
32441    Slick.prototype.keyHandler = function(event) {
32442
32443        var _ = this;
32444         //Dont slide if the cursor is inside the form fields and arrow keys are pressed
32445        if(!event.target.tagName.match('TEXTAREA|INPUT|SELECT')) {
32446            if (event.keyCode === 37 && _.options.accessibility === true) {
32447                _.changeSlide({
32448                    data: {
32449                        message: 'previous'
32450                    }
32451                });
32452            } else if (event.keyCode === 39 && _.options.accessibility === true) {
32453                _.changeSlide({
32454                    data: {
32455                        message: 'next'
32456                    }
32457                });
32458            }
32459        }
32460
32461    };
32462
32463    Slick.prototype.lazyLoad = function() {
32464
32465        var _ = this,
32466            loadRange, cloneRange, rangeStart, rangeEnd;
32467
32468        function loadImages(imagesScope) {
32469            $('img[data-lazy]', imagesScope).each(function() {
32470
32471                var image = $(this),
32472                    imageSource = $(this).attr('data-lazy'),
32473                    imageToLoad = document.createElement('img');
32474
32475                imageToLoad.onload = function() {
32476                    image
32477                        .animate({ opacity: 0 }, 100, function() {
32478                            image
32479                                .attr('src', imageSource)
32480                                .animate({ opacity: 1 }, 200, function() {
32481                                    image
32482                                        .removeAttr('data-lazy')
32483                                        .removeClass('slick-loading');
32484                                });
32485                        });
32486                };
32487
32488                imageToLoad.src = imageSource;
32489
32490            });
32491        }
32492
32493        if (_.options.centerMode === true) {
32494            if (_.options.infinite === true) {
32495                rangeStart = _.currentSlide + (_.options.slidesToShow / 2 + 1);
32496                rangeEnd = rangeStart + _.options.slidesToShow + 2;
32497            } else {
32498                rangeStart = Math.max(0, _.currentSlide - (_.options.slidesToShow / 2 + 1));
32499                rangeEnd = 2 + (_.options.slidesToShow / 2 + 1) + _.currentSlide;
32500            }
32501        } else {
32502            rangeStart = _.options.infinite ? _.options.slidesToShow + _.currentSlide : _.currentSlide;
32503            rangeEnd = rangeStart + _.options.slidesToShow;
32504            if (_.options.fade === true) {
32505                if (rangeStart > 0) rangeStart--;
32506                if (rangeEnd <= _.slideCount) rangeEnd++;
32507            }
32508        }
32509
32510        loadRange = _.$slider.find('.slick-slide').slice(rangeStart, rangeEnd);
32511        loadImages(loadRange);
32512
32513        if (_.slideCount <= _.options.slidesToShow) {
32514            cloneRange = _.$slider.find('.slick-slide');
32515            loadImages(cloneRange);
32516        } else
32517        if (_.currentSlide >= _.slideCount - _.options.slidesToShow) {
32518            cloneRange = _.$slider.find('.slick-cloned').slice(0, _.options.slidesToShow);
32519            loadImages(cloneRange);
32520        } else if (_.currentSlide === 0) {
32521            cloneRange = _.$slider.find('.slick-cloned').slice(_.options.slidesToShow * -1);
32522            loadImages(cloneRange);
32523        }
32524
32525    };
32526
32527    Slick.prototype.loadSlider = function() {
32528
32529        var _ = this;
32530
32531        _.setPosition();
32532
32533        _.$slideTrack.css({
32534            opacity: 1
32535        });
32536
32537        _.$slider.removeClass('slick-loading');
32538
32539        _.initUI();
32540
32541        if (_.options.lazyLoad === 'progressive') {
32542            _.progressiveLazyLoad();
32543        }
32544
32545    };
32546
32547    Slick.prototype.next = Slick.prototype.slickNext = function() {
32548
32549        var _ = this;
32550
32551        _.changeSlide({
32552            data: {
32553                message: 'next'
32554            }
32555        });
32556
32557    };
32558
32559    Slick.prototype.orientationChange = function() {
32560
32561        var _ = this;
32562
32563        _.checkResponsive();
32564        _.setPosition();
32565
32566    };
32567
32568    Slick.prototype.pause = Slick.prototype.slickPause = function() {
32569
32570        var _ = this;
32571
32572        _.autoPlayClear();
32573        _.paused = true;
32574
32575    };
32576
32577    Slick.prototype.play = Slick.prototype.slickPlay = function() {
32578
32579        var _ = this;
32580
32581        _.paused = false;
32582        _.autoPlay();
32583
32584    };
32585
32586    Slick.prototype.postSlide = function(index) {
32587
32588        var _ = this;
32589
32590        _.$slider.trigger('afterChange', [_, index]);
32591
32592        _.animating = false;
32593
32594        _.setPosition();
32595
32596        _.swipeLeft = null;
32597
32598        if (_.options.autoplay === true && _.paused === false) {
32599            _.autoPlay();
32600        }
32601        if (_.options.accessibility === true) {
32602            _.initADA();
32603        }
32604
32605    };
32606
32607    Slick.prototype.prev = Slick.prototype.slickPrev = function() {
32608
32609        var _ = this;
32610
32611        _.changeSlide({
32612            data: {
32613                message: 'previous'
32614            }
32615        });
32616
32617    };
32618
32619    Slick.prototype.preventDefault = function(event) {
32620        event.preventDefault();
32621    };
32622
32623    Slick.prototype.progressiveLazyLoad = function() {
32624
32625        var _ = this,
32626            imgCount, targetImage;
32627
32628        imgCount = $('img[data-lazy]', _.$slider).length;
32629
32630        if (imgCount > 0) {
32631            targetImage = $('img[data-lazy]', _.$slider).first();
32632            targetImage.attr('src', null);
32633            targetImage.attr('src', targetImage.attr('data-lazy')).removeClass('slick-loading').load(function() {
32634                    targetImage.removeAttr('data-lazy');
32635                    _.progressiveLazyLoad();
32636
32637                    if (_.options.adaptiveHeight === true) {
32638                        _.setPosition();
32639                    }
32640                })
32641                .error(function() {
32642                    targetImage.removeAttr('data-lazy');
32643                    _.progressiveLazyLoad();
32644                });
32645        }
32646
32647    };
32648
32649    Slick.prototype.refresh = function( initializing ) {
32650
32651        var _ = this, currentSlide, firstVisible;
32652
32653        firstVisible = _.slideCount - _.options.slidesToShow;
32654
32655        // check that the new breakpoint can actually accept the
32656        // "current slide" as the current slide, otherwise we need
32657        // to set it to the closest possible value.
32658        if ( !_.options.infinite ) {
32659            if ( _.slideCount <= _.options.slidesToShow ) {
32660                _.currentSlide = 0;
32661            } else if ( _.currentSlide > firstVisible ) {
32662                _.currentSlide = firstVisible;
32663            }
32664        }
32665
32666         currentSlide = _.currentSlide;
32667
32668        _.destroy(true);
32669
32670        $.extend(_, _.initials, { currentSlide: currentSlide });
32671
vendor: 29,404 bytes, lines 32672-33624
32672        _.init();
32673
32674        if( !initializing ) {
32675
32676            _.changeSlide({
32677                data: {
32678                    message: 'index',
32679                    index: currentSlide
32680                }
32681            }, false);
32682
32683        }
32684
32685    };
32686
32687    Slick.prototype.registerBreakpoints = function() {
32688
32689        var _ = this, breakpoint, currentBreakpoint, l,
32690            responsiveSettings = _.options.responsive || null;
32691
32692        if ( $.type(responsiveSettings) === "array" && responsiveSettings.length ) {
32693
32694            _.respondTo = _.options.respondTo || 'window';
32695
32696            for ( breakpoint in responsiveSettings ) {
32697
32698                l = _.breakpoints.length-1;
32699                currentBreakpoint = responsiveSettings[breakpoint].breakpoint;
32700
32701                if (responsiveSettings.hasOwnProperty(breakpoint)) {
32702
32703                    // loop through the breakpoints and cut out any existing
32704                    // ones with the same breakpoint number, we don't want dupes.
32705                    while( l >= 0 ) {
32706                        if( _.breakpoints[l] && _.breakpoints[l] === currentBreakpoint ) {
32707                            _.breakpoints.splice(l,1);
32708                        }
32709                        l--;
32710                    }
32711
32712                    _.breakpoints.push(currentBreakpoint);
32713                    _.breakpointSettings[currentBreakpoint] = responsiveSettings[breakpoint].settings;
32714
32715                }
32716
32717            }
32718
32719            _.breakpoints.sort(function(a, b) {
32720                return ( _.options.mobileFirst ) ? a-b : b-a;
32721            });
32722
32723        }
32724
32725    };
32726
32727    Slick.prototype.reinit = function() {
32728
32729        var _ = this;
32730
32731        _.$slides =
32732            _.$slideTrack
32733                .children(_.options.slide)
32734                .addClass('slick-slide');
32735
32736        _.slideCount = _.$slides.length;
32737
32738        if (_.currentSlide >= _.slideCount && _.currentSlide !== 0) {
32739            _.currentSlide = _.currentSlide - _.options.slidesToScroll;
32740        }
32741
32742        if (_.slideCount <= _.options.slidesToShow) {
32743            _.currentSlide = 0;
32744        }
32745
32746        _.registerBreakpoints();
32747
32748        _.setProps();
32749        _.setupInfinite();
32750        _.buildArrows();
32751        _.updateArrows();
32752        _.initArrowEvents();
32753        _.buildDots();
32754        _.updateDots();
32755        _.initDotEvents();
32756
32757        _.checkResponsive(false, true);
32758
32759        if (_.options.focusOnSelect === true) {
32760            $(_.$slideTrack).children().on('click.slick', _.selectHandler);
32761        }
32762
32763        _.setSlideClasses(0);
32764
32765        _.setPosition();
32766
32767        _.$slider.trigger('reInit', [_]);
32768
32769        if (_.options.autoplay === true) {
32770            _.focusHandler();
32771        }
32772
32773    };
32774
32775    Slick.prototype.resize = function() {
32776
32777        var _ = this;
32778
32779        if ($(window).width() !== _.windowWidth) {
32780            clearTimeout(_.windowDelay);
32781            _.windowDelay = window.setTimeout(function() {
32782                _.windowWidth = $(window).width();
32783                _.checkResponsive();
32784                if( !_.unslicked ) { _.setPosition(); }
32785            }, 50);
32786        }
32787    };
32788
32789    Slick.prototype.removeSlide = Slick.prototype.slickRemove = function(index, removeBefore, removeAll) {
32790
32791        var _ = this;
32792
32793        if (typeof(index) === 'boolean') {
32794            removeBefore = index;
32795            index = removeBefore === true ? 0 : _.slideCount - 1;
32796        } else {
32797            index = removeBefore === true ? --index : index;
32798        }
32799
32800        if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) {
32801            return false;
32802        }
32803
32804        _.unload();
32805
32806        if (removeAll === true) {
32807            _.$slideTrack.children().remove();
32808        } else {
32809            _.$slideTrack.children(this.options.slide).eq(index).remove();
32810        }
32811
32812        _.$slides = _.$slideTrack.children(this.options.slide);
32813
32814        _.$slideTrack.children(this.options.slide).detach();
32815
32816        _.$slideTrack.append(_.$slides);
32817
32818        _.$slidesCache = _.$slides;
32819
32820        _.reinit();
32821
32822    };
32823
32824    Slick.prototype.setCSS = function(position) {
32825
32826        var _ = this,
32827            positionProps = {},
32828            x, y;
32829
32830        if (_.options.rtl === true) {
32831            position = -position;
32832        }
32833        x = _.positionProp == 'left' ? Math.ceil(position) + 'px' : '0px';
32834        y = _.positionProp == 'top' ? Math.ceil(position) + 'px' : '0px';
32835
32836        positionProps[_.positionProp] = position;
32837
32838        if (_.transformsEnabled === false) {
32839            _.$slideTrack.css(positionProps);
32840        } else {
32841            positionProps = {};
32842            if (_.cssTransitions === false) {
32843                positionProps[_.animType] = 'translate(' + x + ', ' + y + ')';
32844                _.$slideTrack.css(positionProps);
32845            } else {
32846                positionProps[_.animType] = 'translate3d(' + x + ', ' + y + ', 0px)';
32847                _.$slideTrack.css(positionProps);
32848            }
32849        }
32850
32851    };
32852
32853    Slick.prototype.setDimensions = function() {
32854
32855        var _ = this;
32856
32857        if (_.options.vertical === false) {
32858            if (_.options.centerMode === true) {
32859                _.$list.css({
32860                    padding: ('0px ' + _.options.centerPadding)
32861                });
32862            }
32863        } else {
32864            _.$list.height(_.$slides.first().outerHeight(true) * _.options.slidesToShow);
32865            if (_.options.centerMode === true) {
32866                _.$list.css({
32867                    padding: (_.options.centerPadding + ' 0px')
32868                });
32869            }
32870        }
32871
32872        _.listWidth = _.$list.width();
32873        _.listHeight = _.$list.height();
32874
32875
32876        if (_.options.vertical === false && _.options.variableWidth === false) {
32877            _.slideWidth = Math.ceil(_.listWidth / _.options.slidesToShow);
32878            _.$slideTrack.width(Math.ceil((_.slideWidth * _.$slideTrack.children('.slick-slide').length)));
32879
32880        } else if (_.options.variableWidth === true) {
32881            _.$slideTrack.width(5000 * _.slideCount);
32882        } else {
32883            _.slideWidth = Math.ceil(_.listWidth);
32884            _.$slideTrack.height(Math.ceil((_.$slides.first().outerHeight(true) * _.$slideTrack.children('.slick-slide').length)));
32885        }
32886
32887        var offset = _.$slides.first().outerWidth(true) - _.$slides.first().width();
32888        if (_.options.variableWidth === false) _.$slideTrack.children('.slick-slide').width(_.slideWidth - offset);
32889
32890    };
32891
32892    Slick.prototype.setFade = function() {
32893
32894        var _ = this,
32895            targetLeft;
32896
32897        _.$slides.each(function(index, element) {
32898            targetLeft = (_.slideWidth * index) * -1;
32899            if (_.options.rtl === true) {
32900                $(element).css({
32901                    position: 'relative',
32902                    right: targetLeft,
32903                    top: 0,
32904                    zIndex: _.options.zIndex - 2,
32905                    opacity: 0
32906                });
32907            } else {
32908                $(element).css({
32909                    position: 'relative',
32910                    left: targetLeft,
32911                    top: 0,
32912                    zIndex: _.options.zIndex - 2,
32913                    opacity: 0
32914                });
32915            }
32916        });
32917
32918        _.$slides.eq(_.currentSlide).css({
32919            zIndex: _.options.zIndex - 1,
32920            opacity: 1
32921        });
32922
32923    };
32924
32925    Slick.prototype.setHeight = function() {
32926
32927        var _ = this;
32928
32929        if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {
32930            var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);
32931            _.$list.css('height', targetHeight);
32932        }
32933
32934    };
32935
32936    Slick.prototype.setOption = Slick.prototype.slickSetOption = function(option, value, refresh) {
32937
32938        var _ = this, l, item;
32939
32940        if( option === "responsive" && $.type(value) === "array" ) {
32941            for ( item in value ) {
32942                if( $.type( _.options.responsive ) !== "array" ) {
32943                    _.options.responsive = [ value[item] ];
32944                } else {
32945                    l = _.options.responsive.length-1;
32946                    // loop through the responsive object and splice out duplicates.
32947                    while( l >= 0 ) {
32948                        if( _.options.responsive[l].breakpoint === value[item].breakpoint ) {
32949                            _.options.responsive.splice(l,1);
32950                        }
32951                        l--;
32952                    }
32953                    _.options.responsive.push( value[item] );
32954                }
32955            }
32956        } else {
32957            _.options[option] = value;
32958        }
32959
32960        if (refresh === true) {
32961            _.unload();
32962            _.reinit();
32963        }
32964
32965    };
32966
32967    Slick.prototype.setPosition = function() {
32968
32969        var _ = this;
32970
32971        _.setDimensions();
32972
32973        _.setHeight();
32974
32975        if (_.options.fade === false) {
32976            _.setCSS(_.getLeft(_.currentSlide));
32977        } else {
32978            _.setFade();
32979        }
32980
32981        _.$slider.trigger('setPosition', [_]);
32982
32983    };
32984
32985    Slick.prototype.setProps = function() {
32986
32987        var _ = this,
32988            bodyStyle = document.body.style;
32989
32990        _.positionProp = _.options.vertical === true ? 'top' : 'left';
32991
32992        if (_.positionProp === 'top') {
32993            _.$slider.addClass('slick-vertical');
32994        } else {
32995            _.$slider.removeClass('slick-vertical');
32996        }
32997
32998        if (bodyStyle.WebkitTransition !== undefined ||
32999            bodyStyle.MozTransition !== undefined ||
33000            bodyStyle.msTransition !== undefined) {
33001            if (_.options.useCSS === true) {
33002                _.cssTransitions = true;
33003            }
33004        }
33005
33006        if ( _.options.fade ) {
33007            if ( typeof _.options.zIndex === 'number' ) {
33008                if( _.options.zIndex < 3 ) {
33009                    _.options.zIndex = 3;
33010                }
33011            } else {
33012                _.options.zIndex = _.defaults.zIndex;
33013            }
33014        }
33015
33016        if (bodyStyle.OTransform !== undefined) {
33017            _.animType = 'OTransform';
33018            _.transformType = '-o-transform';
33019            _.transitionType = 'OTransition';
33020            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
33021        }
33022        if (bodyStyle.MozTransform !== undefined) {
33023            _.animType = 'MozTransform';
33024            _.transformType = '-moz-transform';
33025            _.transitionType = 'MozTransition';
33026            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.MozPerspective === undefined) _.animType = false;
33027        }
33028        if (bodyStyle.webkitTransform !== undefined) {
33029            _.animType = 'webkitTransform';
33030            _.transformType = '-webkit-transform';
33031            _.transitionType = 'webkitTransition';
33032            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
33033        }
33034        if (bodyStyle.msTransform !== undefined) {
33035            _.animType = 'msTransform';
33036            _.transformType = '-ms-transform';
33037            _.transitionType = 'msTransition';
33038            if (bodyStyle.msTransform === undefined) _.animType = false;
33039        }
33040        if (bodyStyle.transform !== undefined && _.animType !== false) {
33041            _.animType = 'transform';
33042            _.transformType = 'transform';
33043            _.transitionType = 'transition';
33044        }
33045        _.transformsEnabled = _.options.useTransform && (_.animType !== null && _.animType !== false);
33046    };
33047
33048
33049    Slick.prototype.setSlideClasses = function(index) {
33050
33051        var _ = this,
33052            centerOffset, allSlides, indexOffset, remainder;
33053
33054        allSlides = _.$slider
33055            .find('.slick-slide')
33056            .removeClass('slick-active slick-center slick-current')
33057            .attr('aria-hidden', 'true');
33058
33059        _.$slides
33060            .eq(index)
33061            .addClass('slick-current');
33062
33063        if (_.options.centerMode === true) {
33064
33065            centerOffset = Math.floor(_.options.slidesToShow / 2);
33066
33067            if (_.options.infinite === true) {
33068
33069                if (index >= centerOffset && index <= (_.slideCount - 1) - centerOffset) {
33070
33071                    _.$slides
33072                        .slice(index - centerOffset, index + centerOffset + 1)
33073                        .addClass('slick-active')
33074                        .attr('aria-hidden', 'false');
33075
33076                } else {
33077
33078                    indexOffset = _.options.slidesToShow + index;
33079                    allSlides
33080                        .slice(indexOffset - centerOffset + 1, indexOffset + centerOffset + 2)
33081                        .addClass('slick-active')
33082                        .attr('aria-hidden', 'false');
33083
33084                }
33085
33086                if (index === 0) {
33087
33088                    allSlides
33089                        .eq(allSlides.length - 1 - _.options.slidesToShow)
33090                        .addClass('slick-center');
33091
33092                } else if (index === _.slideCount - 1) {
33093
33094                    allSlides
33095                        .eq(_.options.slidesToShow)
33096                        .addClass('slick-center');
33097
33098                }
33099
33100            }
33101
33102            _.$slides
33103                .eq(index)
33104                .addClass('slick-center');
33105
33106        } else {
33107
33108            if (index >= 0 && index <= (_.slideCount - _.options.slidesToShow)) {
33109
33110                _.$slides
33111                    .slice(index, index + _.options.slidesToShow)
33112                    .addClass('slick-active')
33113                    .attr('aria-hidden', 'false');
33114
33115            } else if (allSlides.length <= _.options.slidesToShow) {
33116
33117                allSlides
33118                    .addClass('slick-active')
33119                    .attr('aria-hidden', 'false');
33120
33121            } else {
33122
33123                remainder = _.slideCount % _.options.slidesToShow;
33124                indexOffset = _.options.infinite === true ? _.options.slidesToShow + index : index;
33125
33126                if (_.options.slidesToShow == _.options.slidesToScroll && (_.slideCount - index) < _.options.slidesToShow) {
33127
33128                    allSlides
33129                        .slice(indexOffset - (_.options.slidesToShow - remainder), indexOffset + remainder)
33130                        .addClass('slick-active')
33131                        .attr('aria-hidden', 'false');
33132
33133                } else {
33134
33135                    allSlides
33136                        .slice(indexOffset, indexOffset + _.options.slidesToShow)
33137                        .addClass('slick-active')
33138                        .attr('aria-hidden', 'false');
33139
33140                }
33141
33142            }
33143
33144        }
33145
33146        if (_.options.lazyLoad === 'ondemand') {
33147            _.lazyLoad();
33148        }
33149
33150    };
33151
33152    Slick.prototype.setupInfinite = function() {
33153
33154        var _ = this,
33155            i, slideIndex, infiniteCount;
33156
33157        if (_.options.fade === true) {
33158            _.options.centerMode = false;
33159        }
33160
33161        if (_.options.infinite === true && _.options.fade === false) {
33162
33163            slideIndex = null;
33164
33165            if (_.slideCount > _.options.slidesToShow) {
33166
33167                if (_.options.centerMode === true) {
33168                    infiniteCount = _.options.slidesToShow + 1;
33169                } else {
33170                    infiniteCount = _.options.slidesToShow;
33171                }
33172
33173                for (i = _.slideCount; i > (_.slideCount -
33174                        infiniteCount); i -= 1) {
33175                    slideIndex = i - 1;
33176                    $(_.$slides[slideIndex]).clone(true).attr('id', '')
33177                        .attr('data-slick-index', slideIndex - _.slideCount)
33178                        .prependTo(_.$slideTrack).addClass('slick-cloned');
33179                }
33180                for (i = 0; i < infiniteCount; i += 1) {
33181                    slideIndex = i;
33182                    $(_.$slides[slideIndex]).clone(true).attr('id', '')
33183                        .attr('data-slick-index', slideIndex + _.slideCount)
33184                        .appendTo(_.$slideTrack).addClass('slick-cloned');
33185                }
33186                _.$slideTrack.find('.slick-cloned').find('[id]').each(function() {
33187                    $(this).attr('id', '');
33188                });
33189
33190            }
33191
33192        }
33193
33194    };
33195
33196    Slick.prototype.setPaused = function(paused) {
33197
33198        var _ = this;
33199
33200        if (_.options.autoplay === true && _.options.pauseOnHover === true) {
33201            _.paused = paused;
33202            if (!paused) {
33203                _.autoPlay();
33204            } else {
33205                _.autoPlayClear();
33206            }
33207        }
33208    };
33209
33210    Slick.prototype.selectHandler = function(event) {
33211
33212        var _ = this;
33213
33214        var targetElement =
33215            $(event.target).is('.slick-slide') ?
33216                $(event.target) :
33217                $(event.target).parents('.slick-slide');
33218
33219        var index = parseInt(targetElement.attr('data-slick-index'));
33220
33221        if (!index) index = 0;
33222
33223        if (_.slideCount <= _.options.slidesToShow) {
33224
33225            _.setSlideClasses(index);
33226            _.asNavFor(index);
33227            return;
33228
33229        }
33230
33231        _.slideHandler(index);
33232
33233    };
33234
33235    Slick.prototype.slideHandler = function(index, sync, dontAnimate) {
33236
33237        var targetSlide, animSlide, oldSlide, slideLeft, targetLeft = null,
33238            _ = this;
33239
33240        sync = sync || false;
33241
33242        if (_.animating === true && _.options.waitForAnimate === true) {
33243            return;
33244        }
33245
33246        if (_.options.fade === true && _.currentSlide === index) {
33247            return;
33248        }
33249
33250        if (_.slideCount <= _.options.slidesToShow) {
33251            return;
33252        }
33253
33254        if (sync === false) {
33255            _.asNavFor(index);
33256        }
33257
33258        targetSlide = index;
33259        targetLeft = _.getLeft(targetSlide);
33260        slideLeft = _.getLeft(_.currentSlide);
33261
33262        _.currentLeft = _.swipeLeft === null ? slideLeft : _.swipeLeft;
33263
33264        if (_.options.infinite === false && _.options.centerMode === false && (index < 0 || index > _.getDotCount() * _.options.slidesToScroll)) {
33265            if (_.options.fade === false) {
33266                targetSlide = _.currentSlide;
33267                if (dontAnimate !== true) {
33268                    _.animateSlide(slideLeft, function() {
33269                        _.postSlide(targetSlide);
33270                    });
33271                } else {
33272                    _.postSlide(targetSlide);
33273                }
33274            }
33275            return;
33276        } else if (_.options.infinite === false && _.options.centerMode === true && (index < 0 || index > (_.slideCount - _.options.slidesToScroll))) {
33277            if (_.options.fade === false) {
33278                targetSlide = _.currentSlide;
33279                if (dontAnimate !== true) {
33280                    _.animateSlide(slideLeft, function() {
33281                        _.postSlide(targetSlide);
33282                    });
33283                } else {
33284                    _.postSlide(targetSlide);
33285                }
33286            }
33287            return;
33288        }
33289
33290        if (_.options.autoplay === true) {
33291            clearInterval(_.autoPlayTimer);
33292        }
33293
33294        if (targetSlide < 0) {
33295            if (_.slideCount % _.options.slidesToScroll !== 0) {
33296                animSlide = _.slideCount - (_.slideCount % _.options.slidesToScroll);
33297            } else {
33298                animSlide = _.slideCount + targetSlide;
33299            }
33300        } else if (targetSlide >= _.slideCount) {
33301            if (_.slideCount % _.options.slidesToScroll !== 0) {
33302                animSlide = 0;
33303            } else {
33304                animSlide = targetSlide - _.slideCount;
33305            }
33306        } else {
33307            animSlide = targetSlide;
33308        }
33309
33310        _.animating = true;
33311
33312        _.$slider.trigger('beforeChange', [_, _.currentSlide, animSlide]);
33313
33314        oldSlide = _.currentSlide;
33315        _.currentSlide = animSlide;
33316
33317        _.setSlideClasses(_.currentSlide);
33318
33319        _.updateDots();
33320        _.updateArrows();
33321
33322        if (_.options.fade === true) {
33323            if (dontAnimate !== true) {
33324
33325                _.fadeSlideOut(oldSlide);
33326
33327                _.fadeSlide(animSlide, function() {
33328                    _.postSlide(animSlide);
33329                });
33330
33331            } else {
33332                _.postSlide(animSlide);
33333            }
33334            _.animateHeight();
33335            return;
33336        }
33337
33338        if (dontAnimate !== true) {
33339            _.animateSlide(targetLeft, function() {
33340                _.postSlide(animSlide);
33341            });
33342        } else {
33343            _.postSlide(animSlide);
33344        }
33345
33346    };
33347
33348    Slick.prototype.startLoad = function() {
33349
33350        var _ = this;
33351
33352        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
33353
33354            _.$prevArrow.hide();
33355            _.$nextArrow.hide();
33356
33357        }
33358
33359        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
33360
33361            _.$dots.hide();
33362
33363        }
33364
33365        _.$slider.addClass('slick-loading');
33366
33367    };
33368
33369    Slick.prototype.swipeDirection = function() {
33370
33371        var xDist, yDist, r, swipeAngle, _ = this;
33372
33373        xDist = _.touchObject.startX - _.touchObject.curX;
33374        yDist = _.touchObject.startY - _.touchObject.curY;
33375        r = Math.atan2(yDist, xDist);
33376
33377        swipeAngle = Math.round(r * 180 / Math.PI);
33378        if (swipeAngle < 0) {
33379            swipeAngle = 360 - Math.abs(swipeAngle);
33380        }
33381
33382        if ((swipeAngle <= 45) && (swipeAngle >= 0)) {
33383            return (_.options.rtl === false ? 'left' : 'right');
33384        }
33385        if ((swipeAngle <= 360) && (swipeAngle >= 315)) {
33386            return (_.options.rtl === false ? 'left' : 'right');
33387        }
33388        if ((swipeAngle >= 135) && (swipeAngle <= 225)) {
33389            return (_.options.rtl === false ? 'right' : 'left');
33390        }
33391        if (_.options.verticalSwiping === true) {
33392            if ((swipeAngle >= 35) && (swipeAngle <= 135)) {
33393                return 'left';
33394            } else {
33395                return 'right';
33396            }
33397        }
33398
33399        return 'vertical';
33400
33401    };
33402
33403    Slick.prototype.swipeEnd = function(event) {
33404
33405        var _ = this,
33406            slideCount;
33407
33408        _.dragging = false;
33409
33410        _.shouldClick = (_.touchObject.swipeLength > 10) ? false : true;
33411
33412        if (_.touchObject.curX === undefined) {
33413            return false;
33414        }
33415
33416        if (_.touchObject.edgeHit === true) {
33417            _.$slider.trigger('edge', [_, _.swipeDirection()]);
33418        }
33419
33420        if (_.touchObject.swipeLength >= _.touchObject.minSwipe) {
33421
33422            switch (_.swipeDirection()) {
33423                case 'left':
33424                    slideCount = _.options.swipeToSlide ? _.checkNavigable(_.currentSlide + _.getSlideCount()) : _.currentSlide + _.getSlideCount();
33425                    _.slideHandler(slideCount);
33426                    _.currentDirection = 0;
33427                    _.touchObject = {};
33428                    _.$slider.trigger('swipe', [_, 'left']);
33429                    break;
33430
33431                case 'right':
33432                    slideCount = _.options.swipeToSlide ? _.checkNavigable(_.currentSlide - _.getSlideCount()) : _.currentSlide - _.getSlideCount();
33433                    _.slideHandler(slideCount);
33434                    _.currentDirection = 1;
33435                    _.touchObject = {};
33436                    _.$slider.trigger('swipe', [_, 'right']);
33437                    break;
33438            }
33439        } else {
33440            if (_.touchObject.startX !== _.touchObject.curX) {
33441                _.slideHandler(_.currentSlide);
33442                _.touchObject = {};
33443            }
33444        }
33445
33446    };
33447
33448    Slick.prototype.swipeHandler = function(event) {
33449
33450        var _ = this;
33451
33452        if ((_.options.swipe === false) || ('ontouchend' in document && _.options.swipe === false)) {
33453            return;
33454        } else if (_.options.draggable === false && event.type.indexOf('mouse') !== -1) {
33455            return;
33456        }
33457
33458        _.touchObject.fingerCount = event.originalEvent && event.originalEvent.touches !== undefined ?
33459            event.originalEvent.touches.length : 1;
33460
33461        _.touchObject.minSwipe = _.listWidth / _.options
33462            .touchThreshold;
33463
33464        if (_.options.verticalSwiping === true) {
33465            _.touchObject.minSwipe = _.listHeight / _.options
33466                .touchThreshold;
33467        }
33468
33469        switch (event.data.action) {
33470
33471            case 'start':
33472                _.swipeStart(event);
33473                break;
33474
33475            case 'move':
33476                _.swipeMove(event);
33477                break;
33478
33479            case 'end':
33480                _.swipeEnd(event);
33481                break;
33482
33483        }
33484
33485    };
33486
33487    Slick.prototype.swipeMove = function(event) {
33488
33489        var _ = this,
33490            edgeWasHit = false,
33491            curLeft, swipeDirection, swipeLength, positionOffset, touches;
33492
33493        touches = event.originalEvent !== undefined ? event.originalEvent.touches : null;
33494
33495        if (!_.dragging || touches && touches.length !== 1) {
33496            return false;
33497        }
33498
33499        curLeft = _.getLeft(_.currentSlide);
33500
33501        _.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX;
33502        _.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY;
33503
33504        _.touchObject.swipeLength = Math.round(Math.sqrt(
33505            Math.pow(_.touchObject.curX - _.touchObject.startX, 2)));
33506
33507        if (_.options.verticalSwiping === true) {
33508            _.touchObject.swipeLength = Math.round(Math.sqrt(
33509                Math.pow(_.touchObject.curY - _.touchObject.startY, 2)));
33510        }
33511
33512        swipeDirection = _.swipeDirection();
33513
33514        if (swipeDirection === 'vertical') {
33515            return;
33516        }
33517
33518        if (event.originalEvent !== undefined && _.touchObject.swipeLength > 4) {
33519            event.preventDefault();
33520        }
33521
33522        positionOffset = (_.options.rtl === false ? 1 : -1) * (_.touchObject.curX > _.touchObject.startX ? 1 : -1);
33523        if (_.options.verticalSwiping === true) {
33524            positionOffset = _.touchObject.curY > _.touchObject.startY ? 1 : -1;
33525        }
33526
33527
33528        swipeLength = _.touchObject.swipeLength;
33529
33530        _.touchObject.edgeHit = false;
33531
33532        if (_.options.infinite === false) {
33533            if ((_.currentSlide === 0 && swipeDirection === 'right') || (_.currentSlide >= _.getDotCount() && swipeDirection === 'left')) {
33534                swipeLength = _.touchObject.swipeLength * _.options.edgeFriction;
33535                _.touchObject.edgeHit = true;
33536            }
33537        }
33538
33539        if (_.options.vertical === false) {
33540            _.swipeLeft = curLeft + swipeLength * positionOffset;
33541        } else {
33542            _.swipeLeft = curLeft + (swipeLength * (_.$list.height() / _.listWidth)) * positionOffset;
33543        }
33544        if (_.options.verticalSwiping === true) {
33545            _.swipeLeft = curLeft + swipeLength * positionOffset;
33546        }
33547
33548        if (_.options.fade === true || _.options.touchMove === false) {
33549            return false;
33550        }
33551
33552        if (_.animating === true) {
33553            _.swipeLeft = null;
33554            return false;
33555        }
33556
33557        _.setCSS(_.swipeLeft);
33558
33559    };
33560
33561    Slick.prototype.swipeStart = function(event) {
33562
33563        var _ = this,
33564            touches;
33565
33566        if (_.touchObject.fingerCount !== 1 || _.slideCount <= _.options.slidesToShow) {
33567            _.touchObject = {};
33568            return false;
33569        }
33570
33571        if (event.originalEvent !== undefined && event.originalEvent.touches !== undefined) {
33572            touches = event.originalEvent.touches[0];
33573        }
33574
33575        _.touchObject.startX = _.touchObject.curX = touches !== undefined ? touches.pageX : event.clientX;
33576        _.touchObject.startY = _.touchObject.curY = touches !== undefined ? touches.pageY : event.clientY;
33577
33578        _.dragging = true;
33579
33580    };
33581
33582    Slick.prototype.unfilterSlides = Slick.prototype.slickUnfilter = function() {
33583
33584        var _ = this;
33585
33586        if (_.$slidesCache !== null) {
33587
33588            _.unload();
33589
33590            _.$slideTrack.children(this.options.slide).detach();
33591
33592            _.$slidesCache.appendTo(_.$slideTrack);
33593
33594            _.reinit();
33595
33596        }
33597
33598    };
33599
33600    Slick.prototype.unload = function() {
33601
33602        var _ = this;
33603
33604        $('.slick-cloned', _.$slider).remove();
33605
33606        if (_.$dots) {
33607            _.$dots.remove();
33608        }
33609
33610        if (_.$prevArrow && _.htmlExpr.test(_.options.prevArrow)) {
33611            _.$prevArrow.remove();
33612        }
33613
33614        if (_.$nextArrow && _.htmlExpr.test(_.options.nextArrow)) {
33615            _.$nextArrow.remove();
33616        }
33617
33618        _.$slides
33619            .removeClass('slick-slide slick-active slick-visible slick-current')
33620            .attr('aria-hidden', 'true')
33621            .css('width', '');
33622
33623    };
33624
33625    Slick.prototype.unslick = function(fromBreakpoint) {
33626
33627        var _ = this;
33628        _.$slider.trigger('unslick', [_, fromBreakpoint]);
33629        _.destroy();
33630
33631    };
33632
33633    Slick.prototype.updateArrows = function() {
33634
33635        var _ = this,
33636            centerOffset;
33637
33638        centerOffset = Math.floor(_.options.slidesToShow / 2);
33639
33640        if ( _.options.arrows === true &&
33641            _.slideCount > _.options.slidesToShow &&
33642            !_.options.infinite ) {
33643
33644            _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
33645            _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
33646
33647            if (_.currentSlide === 0) {
33648
33649                _.$prevArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
33650                _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
33651
33652            } else if (_.currentSlide >= _.slideCount - _.options.slidesToShow && _.options.centerMode === false) {
33653
33654                _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
33655                _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
33656
33657            } else if (_.currentSlide >= _.slideCount - 1 && _.options.centerMode === true) {
33658
33659                _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
33660                _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
33661
33662            }
33663
33664        }
33665
33666    };
33667
33668    Slick.prototype.updateDots = function() {
33669
33670        var _ = this;
33671
33672        if (_.$dots !== null) {
33673
33674            _.$dots
33675                .find('li')
33676                .removeClass('slick-active')
33677                .attr('aria-hidden', 'true');
33678
33679            _.$dots
33680                .find('li')
33681                .eq(Math.floor(_.currentSlide / _.options.slidesToScroll))
33682                .addClass('slick-active')
33683                .attr('aria-hidden', 'false');
33684
33685        }
33686
33687    };
33688
33689    Slick.prototype.visibility = function() {
33690
33691        var _ = this;
33692
33693        if (document[_.hidden]) {
33694            _.paused = true;
33695            _.autoPlayClear();
33696        } else {
33697            if (_.options.autoplay === true) {
33698                _.paused = false;
33699                _.autoPlay();
33700            }
33701        }
33702
33703    };
33704    Slick.prototype.initADA = function() {
33705        var _ = this;
33706        _.$slides.add(_.$slideTrack.find('.slick-cloned')).attr({
33707            'aria-hidden': 'true',
33708            'tabindex': '-1'
33709        }).find('a, input, button, select').attr({
33710            'tabindex': '-1'
33711        });
33712
33713        _.$slideTrack.attr('role', 'listbox');
33714
33715        _.$slides.not(_.$slideTrack.find('.slick-cloned')).each(function(i) {
33716            $(this).attr({
33717                'role': 'option',
33718                'aria-describedby': 'slick-slide' + _.instanceUid + i + ''
33719            });
33720        });
33721
33722        if (_.$dots !== null) {
33723            _.$dots.attr('role', 'tablist').find('li').each(function(i) {
33724                $(this).attr({
33725                    'role': 'presentation',
33726                    'aria-selected': 'false',
33727                    'aria-controls': 'navigation' + _.instanceUid + i + '',
33728                    'id': 'slick-slide' + _.instanceUid + i + ''
33729                });
33730            })
33731                .first().attr('aria-selected', 'true').end()
33732                .find('button').attr('role', 'button').end()
33733                .closest('div').attr('role', 'toolbar');
33734        }
33735        _.activateADA();
33736
33737    };
33738
33739    Slick.prototype.activateADA = function() {
33740        var _ = this;
33741
33742        _.$slideTrack.find('.slick-active').attr({
33743            'aria-hidden': 'false'
33744        }).find('a, input, button, select').attr({
33745            'tabindex': '0'
33746        });
33747
33748    };
33749
33750    Slick.prototype.focusHandler = function() {
33751        var _ = this;
33752        _.$slider.on('focus.slick blur.slick', '*', function(event) {
33753            event.stopImmediatePropagation();
33754            var sf = $(this);
33755            setTimeout(function() {
33756                if (_.isPlay) {
33757                    if (sf.is(':focus')) {
33758                        _.autoPlayClear();
33759                        _.paused = true;
33760                    } else {
33761                        _.paused = false;
33762                        _.autoPlay();
33763                    }
33764                }
33765            }, 0);
33766        });
33767    };
33768
33769    $.fn.slick = function() {
33770        var _ = this,
33771            opt = arguments[0],
33772            args = Array.prototype.slice.call(arguments, 1),
33773            l = _.length,
33774            i,
33775            ret;
33776        for (i = 0; i < l; i++) {
33777            if (typeof opt == 'object' || typeof opt == 'undefined')
33778                _[i].slick = new Slick(_[i], opt);
33779            else
33780                ret = _[i].slick[opt].apply(_[i].slick, args);
33781            if (typeof ret != 'undefined') return ret;
33782        }
33783        return _;
33784    };
33785
33786}));
33787
33788// jQuery RoyalSlider plugin. Copyright Dmitry Semenov, http://dim
33788semenov.com 
33789// jquery.royalslider v9.5.4
33790(function(n){function u(b,f){var c,a=this,e=window.navigator,g=e.userAgent.toLowerCase();a.uid=n.rsModules.uid++;a.ns=".rs"+a.uid;var d=document.createElement("div").style,h=["webkit","Moz","ms","O"],k="",l=0,r;for(c=0;c<h.length;c++)r=h[c],!k&&r+"Transform"in d&&(k=r),r=r.toLowerCase(),window.requestAnimationFrame||(window.requestAnimationFrame=window[r+"RequestAnimationFrame"],window.cancelAnimationFrame=window[r+"CancelAnimationFrame"]||window[r+"CancelRequestAnimationFrame"]);window.requestAnimationFrame||
33791(window.requestAnimationFrame=function(a,b){var c=(new Date).getTime(),d=Math.max(0,16-(c-l)),e=window.setTimeout(function(){a(c+d)},d);l=c+d;return e});window.cancelAnimationFrame||(window.cancelAnimationFrame=function(a){clearTimeout(a)});a.isIPAD=g.match(/(ipad)/);a.isIOS=a.isIPAD||g.match(/(iphone|ipod)/);c=function(a){a=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||0>a.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||
33792[];return{browser:a[1]||"",version:a[2]||"0"}}(g);h={};c.browser&&(h[c.browser]=!0,h.version=c.version);h.chrome&&(h.webkit=!0);a._a=h;a.isAndroid=-1<g.indexOf("android");a.slider=n(b);a.ev=n(a);a._b=n(document);a.st=n.extend({},n.fn.royalSlider.defaults,f);a._c=a.st.transitionSpeed;a._d=0;!a.st.allowCSS3||h.webkit&&!a.st.allowCSS3OnWebkit||(c=k+(k?"T":"t"),a._e=c+"ransform"in d&&c+"ransition"in d,a._e&&(a._f=k+(k?"P":"p")+"erspective"in d));k=k.toLowerCase();a._g="-"+k+"-";a._h="vertical"===a.st.slidesOrientation?
33793!1:!0;a._i=a._h?"left":"top";a._j=a._h?"width":"height";a._k=-1;a._l="fade"===a.st.transitionType?!1:!0;a._l||(a.st.sliderDrag=!1,a._m=10);a._n="z-index:0; display:none; opacity:0;";a._o=0;a._p=0;a._q=0;n.each(n.rsModules,function(b,c){"uid"!==b&&c.call(a)});a.slides=[];a._r=0;(a.st.slides?n(a.st.slides):a.slider.children().detach()).each(function(){a._s(this,!0)});a.st.randomizeSlides&&a.slides.sort(function(){return 0.5-Math.random()});a.numSlides=a.slides.length;a._t();a.st.startSlideId?a.st.startSlideId>
33794a.numSlides-1&&(a.st.startSlideId=a.numSlides-1):a.st.startSlideId=0;a._o=a.staticSlideId=a.currSlideId=a._u=a.st.startSlideId;a.currSlide=a.slides[a.currSlideId];a._v=0;a.pointerMultitouch=!1;a.slider.addClass((a._h?"rsHor":"rsVer")+(a._l?"":" rsFade"));d='<div class="rsOverflow"><div class="rsContainer">';a.slidesSpacing=a.st.slidesSpacing;a._w=(a._h?a.slider.width():a.slider.height())+a.st.slidesSpacing;a._x=Boolean(0<a._y);1>=a.numSlides&&(a._z=!1);a._a1=a._z&&a._l?2===a.numSlides?1:2:0;a._b1=
337956>a.numSlides?a.numSlides:6;a._c1=0;a._d1=0;a.slidesJQ=[];for(c=0;c<a.numSlides;c++)a.slidesJQ.push(n('<div style="'+(a._l?"":c!==a.currSlideId?a._n:"z-index:0;")+'" class="rsSlide "></div>'));a._e1=d=n(d+"</div></div>");var m=a.ns,k=function(b,c,d,e,f){a._j1=b+c+m;a._k1=b+d+m;a._l1=b+e+m;f&&(a._m1=b+f+m)};c=e.pointerEnabled;a.pointerEnabled=c||e.msPointerEnabled;a.pointerEnabled?(a.hasTouch=!1,a._n1=0.2,a.pointerMultitouch=Boolean(1<e[(c?"m":"msM")+"axTouchPoints"]),c?k("pointer","down","move","up",
33796"cancel"):k("MSPointer","Down","Move","Up","Cancel")):(a.isIOS?a._j1=a._k1=a._l1=a._m1="":k("mouse","down","move","up"),"ontouchstart"in window||"createTouch"in document?(a.hasTouch=!0,a._j1+=" touchstart"+m,a._k1+=" touchmove"+m,a._l1+=" touchend"+m,a._m1+=" touchcancel"+m,a._n1=0.5,a.st.sliderTouch&&(a._f1=!0)):(a.hasTouch=!1,a._n1=0.2));a.st.sliderDrag&&(a._f1=!0,h.msie||h.opera?a._g1=a._h1="move":h.mozilla?(a._g1="-moz-grab",a._h1="-moz-grabbing"):h.webkit&&-1!=e.platform.indexOf("Mac")&&(a._g1=
33797"-webkit-grab",a._h1="-webkit-grabbing"),a._i1());a.slider.html(d);a._o1=a.st.controlsInside?a._e1:a.slider;a._p1=a._e1.children(".rsContainer");a.pointerEnabled&&a._p1.css((c?"":"-ms-")+"touch-action",a._h?"pan-y":"pan-x");a._q1=n('<div class="rsPreloader"></div>');e=a._p1.children(".rsSlide");a._r1=a.slidesJQ[a.currSlideId];a._s1=0;a._e?(a._t1="transition-property",a._u1="transition-duration",a._v1="transition-timing-function",a._w1=a._x1=a._g+"transform",a._f?(h.webkit&&!h.chrome&&a.slider.addClass("rsWebkit3d"),
33798a._y1="translate3d(",a._z1="px, ",a._a2="px, 0px)"):(a._y1="translate(",a._z1="px, ",a._a2="px)"),a._l?a._p1[a._g+a._t1]=a._g+"transform":(h={},h[a._g+a._t1]="opacity",h[a._g+a._u1]=a.st.transitionSpeed+"ms",h[a._g+a._v1]=a.st.css3easeInOut,e.css(h))):(a._x1="left",a._w1="top");var p;n(window).on("resize"+a.ns,function(){p&&clearTimeout(p);p=setTimeout(function(){a.updateSliderSize()},50)});a.ev.trigger("rsAfterPropsSetup");a.updateSliderSize();a.st.keyboardNavEnabled&&a._b2();a.st.arrowsNavHideOnTouch&&
33799(a.hasTouch||a.pointerMultitouch)&&(a.st.arrowsNav=!1);a.st.arrowsNav&&(e=a._o1,n('<div class="rsArrow rsArrowLeft"><div class="rsArrowIcn"></div></div><div class="rsArrow rsArrowRight"><div class="rsArrowIcn"></div></div>').appendTo(e),a._c2=e.children(".rsArrowLeft").click(function(b){b.preventDefault();a.prev()}),a._d2=e.children(".rsArrowRight").click(function(b){b.preventDefault();a.next()}),a.st.arrowsNavAutoHide&&!a.hasTouch&&(a._c2.addClass("rsHidden"),a._d2.addClass("rsHidden"),e.one("mousemove.arrowshover",
33800function(){a._c2.removeClass("rsHidden");a._d2.removeClass("rsHidden")}),e.hover(function(){a._e2||(a._c2.removeClass("rsHidden"),a._d2.removeClass("rsHidden"))},function(){a._e2||(a._c2.addClass("rsHidden"),a._d2.addClass("rsHidden"))})),a.ev.on("rsOnUpdateNav",function(){a._f2()}
33800),a._f2());if(a._f1)a._p1.on(a._j1,function(b){a._g2(b)});else a.dragSuccess=!1;var q=["rsPlayBtnIcon","rsPlayBtn","rsCloseVideoBtn","rsCloseVideoIcn"];a._p1.click(function(b){if(!a.dragSuccess){var c=n(b.target).attr("class");
33801if(-1!==n.inArray(c,q)&&a.toggleVideo())return!1;if(a.st.navigateByClick&&!a._h2){if(n(b.target).closest(".rsNoDrag",a._r1).length)return!0;a._i2(b)}a.ev.trigger("rsSlideClick",b)}}).on("click.rs","a",function(b){if(a.dragSuccess)return!1;a._h2=!0;setTimeout(function(){a._h2=!1},3)});a.ev.trigger("rsAfterInit")}n.rsModules||(n.rsModules={uid:0});u.prototype={constructor:u,_i2:function(b){b=b[this._h?"pageX":"pageY"]-this._j2;b>=this._q?this.next():0>b&&this.prev()},_t:function(){var b;b=this.st.numImagesToPreload;
33802if(this._z=this.st.loop)2===this.numSlides?(this._z=!1,this.st.loopRewind=!0):2>this.numSlides&&(this.st.loopRewind=this._z=!1);this._z&&0<b&&(4>=this.numSlides?b=1:this.st.numImagesToPreload>(this.numSlides-1)/2&&(b=Math.floor((this.numSlides-1)/2)));this._y=b},_s:function(b,f){function c(b,c){c?g.images.push(b.attr(c)):g.images.push(b.text());if(h){h=!1;g.caption="src"===c?b.attr("alt"):b.contents();g.image=g.images[0];g.videoURL=b.attr("data-rsVideo");var d=b.attr("data-rsw"),e=b.attr("data-rsh");
33803"undefined"!==typeof d&&!1!==d&&"undefined"!==typeof e&&!1!==e?(g.iW=parseInt(d,10),g.iH=parseInt(e,10)):a.st.imgWidth&&a.st.imgHeight&&(g.iW=a.st.imgWidth,g.iH=a.st.imgHeight)}}var a=this,e,g={},d,h=!0;b=n(b);a._k2=b;a.ev.trigger("rsBeforeParseNode",[b,g]);if(!g.stopParsing)return b=a._k2,g.id=a._r,g.contentAdded=!1,a._r++,g.images=[],g.isBig=!1,g.hasCover||(b.hasClass("rsImg")?(d=b,e=!0):(d=b.find(".rsImg"),d.length&&(e=!0)),e?(g.bigImage=d.eq(0).attr("data-rsBigImg"),d.each(function(){var a=n(this);
33804a.is("a")?c(a,"href"):a.is("img")?c(a,"src"):c(a)})):b.is("img")&&(b.addClass("rsImg rsMainSlideImage"),c(b,"src"))),d=b.find(".rsCaption"),d.length&&(g.caption=d.remove()),g.content=b,a.ev.trigger("rsAfterParseNode",[b,g]),f&&a.slides.push(g),0===g.images.length&&(g.isLoaded=!0,g.isRendered=!1,g.isLoading=!1,g.images=null),g},_b2:function(){var b=this,f,c,a=function(a){37===a?b.prev():39===a&&b.next()};b._b.on("keydown"+b.ns,function(e){b._l2||(c=e.keyCode,37!==c&&39!==c||f||(a(c),f=setInterval(function(){a(c)},
33805700)))}).on("keyup"+b.ns,function(a){f&&(clearInterval(f),f=null)})},goTo:function(b,f){b!==this.currSlideId&&this._m2(b,this.st.transitionSpeed,!0,!f)},destroy:function(b){this.ev.trigger("rsBeforeDestroy");this._b.off("keydown"+this.ns+" keyup"+this.ns+" "+this._k1+" "+this._l1);this._p1.off(this._j1+" click");this.slider.data("royalSlider",null);n.removeData(this.slider,"royalSlider");n(window).off("resize"+this.ns);this.loadingTimeout&&clearTimeout(this.loadingTimeout);b&&this.slider.remove();
33806this.ev=this.slider=this.slides=null},_n2:function(b,f){function c(c,f,g){c.isAdded?(a(f,c),e(f,c)):(g||(g=d.slidesJQ[f]),c.holder?g=c.holder:(g=d.slidesJQ[f]=n(g),c.holder=g),c.appendOnLoaded=!1,e(f,c,g),a(f,c),d._p2(c,g,b),c.isAdded=!0)}function a(a,c){c.contentAdded||(d.setItemHtml(c,b),b||(c.contentAdded=!0))}function e(a,b,c){d._l&&(c||(c=d.slidesJQ[a]),c.css(d._i,(a+d._d1+p)*d._w))}function g(a){if(l){if(a>r-1)return g(a-r);if(0>a)return g(r+a)}return a}var d=this,h,k,l=d._z,r=d.numSlides;if(!isNaN(f))return g(f);
33807var m=d.currSlideId,p,q=b?Math.abs(d._o2-d.currSlideId)>=d.numSlides-1?0:1:d._y,s=Math.min(2,q),v=!1,u=!1,t;for(k=m;k<m+1+s;k++)if(t=g(k),(h=d.slides[t])&&(!h.isAdded||!h.positionSet)){v=!0;break}for(k=m-1;k>m-1-s;k--)if(t=g(k),(h=d.slides[t])&&(!h.isAdded||!h.positionSet)){u=!0;break}if(v)for(k=m;k<m+q+1;k++)t=g(k),p=Math.floor((d._u-(m-k))/d.numSlides)*d.numSlides,(h=d.slides[t])&&c(h,t);if(u)for(k=m-1;k>m-1-q;k--)t=g(k),p=Math.floor((d._u-(m-k))/r)*r,(h=d.slides[t])&&c(h,t);if(!b)for(s=g(m-q),
33808m=g(m+q),q=s>m?0:s,k=0;k<r;k++)s>m&&k>s-1||!(k<q||k>m)||(h=d.slides[k])&&h.holder&&(h.holder.detach(),h.isAdded=!1)},setItemHtml:function(b,f){var c=this,a=function(){if(!b.images)b.isRendered=!0,b.isLoaded=!0,b.isLoading=!1,d(!0);else if(!b.isLoading){var a,f;b.content.hasClass("rsImg")?(a=b.content,f=!0):a=b.content.find(".rsImg:not(img)");a&&!a.is("img")&&a.each(function(){var a=n(this),c='<img class="rsImg" src="'+(a.is("a")?a.attr("href"):a.text())+'" />';f?b.content=n(c):a.replaceWith(c)});
33809a=f?b.content:b.content.find("img.rsImg");k();a.eq(0).addClass("rsMainSlideImage");b.iW&&b.iH&&(b.isLoaded||c._q2(b),d());b.isLoading=!0;if(b.isBig)n("<img />").on("load.rs error.rs",function(a){n(this).off("load.rs error.rs");e([this],!0)}).attr("src",b.image);else{b.loaded=[];b.numStartedLoad=0;a=function(a){n(this).off("load.rs error.rs");b.loaded.push(this);b.loaded.length===b.numStartedLoad&&e(b.loaded,!1)};for(var g=0;g<b.images.length;g++){var h=n("<img />");b.numStartedLoad++;h.on("load.rs error.rs",
33810a).attr("src",b.images[g])}}}},e=function(a,c){if(a.length){var d=a[0];if(c!==b.isBig)(d=b.holder.children())&&1<d.length&&l();else if(b.iW&&b.iH)g();else if(b.iW=d.width,b.iH=d.height,b.iW&&b.iH)g();else{var e=new Image;
33810e.onload=function(){e.width?(b.iW=e.width,b.iH=e.height,g()):setTimeout(function(){e.width&&(b.iW=e.width,b.iH=e.height);g()},1E3)};e.src=d.src}}else g()},g=function(){b.isLoaded=!0;b.isLoading=!1;d();l();h()},d=function(){if(!b.isAppended&&c.ev){var a=c.st.visibleNearby,d=b.id-c._o;
33811f||b.appendOnLoaded||!c.st.fadeinLoadedSlide||0!==d&&(!(a||c._r2||c._l2)||-1!==d&&1!==d)||(a={visibility:"visible",opacity:0},a[c._g+"transition"]="opacity 400ms ease-in-out",b.content.css(a),setTimeout(function(){b.content.css("opacity",1)},16));b.holder.find(".rsPreloader").length?b.holder.append(b.content):b.holder.html(b.content);b.isAppended=!0;b.isLoaded&&(c._q2(b),h());b.sizeReady||(b.sizeReady=!0,setTimeout(function(){c.ev.trigger("rsMaybeSizeReady",b)},100))}},h=function(){!b.loadedTriggered&&
33812c.ev&&(b.isLoaded=b.loadedTriggered=!0,b.holder.trigger("rsAfterContentSet"),c.ev.trigger("rsAfterContentSet",b))},k=function(){c.st.usePreloader&&b.holder.html(c._q1.clone())},l=function(a){c.st.usePreloader&&(a=b.holder.find(".rsPreloader"),a.length&&a.remove())};b.isLoaded?d():f?!c._l&&b.images&&b.iW&&b.iH?a():(b.holder.isWaiting=!0,k(),b.holder.slideId=-99):a()},_p2:function(b,f,c){this._p1.append(b.holder);b.appendOnLoaded=!1},_g2:function(b,f){var c=this,a,e="touchstart"===b.type;c._s2=e;c.ev.trigger("rsDragStart");
33813if(n(b.target).closest(".rsNoDrag",c._r1).length)return c.dragSuccess=!1,!0;!f&&c._r2&&(c._t2=!0,c._u2());c.dragSuccess=!1;if(c._l2)e&&(c._v2=!0);else{e&&(c._v2=!1);c._w2();if(e){var g=b.originalEvent.touches;if(g&&0<g.length)a=g[0],1<g.length&&(c._v2=!0);else return}else b.preventDefault(),a=b,c.pointerEnabled&&(a=a.originalEvent);c._l2=!0;c._b.on(c._k1,function(a){c._x2(a,f)}).on(c._l1,function(a){c._y2(a,f)});c._z2="";c._a3=!1;c._b3=a.pageX;c._c3=a.pageY;c._d3=c._v=(f?c._e3:c._h)?a.pageX:a.pageY;
33814c._f3=0;c._g3=0;c._h3=f?c._i3:c._p;c._j3=(new Date).getTime();if(e)c._e1.on(c._m1,function(a){c._y2(a,f)})}},_k3:function(b,f){if(this._l3){var c=this._m3,a=b.pageX-this._b3,e=b.pageY-this._c3,g=this._h3+a,d=this._h3+e,h=f?this._e3:this._h,g=h?g:d,d=this._z2;this._a3=!0;this._b3=b.pageX;this._c3=b.pageY;"x"===d&&0!==a?this._f3=0<a?1:-1:"y"===d&&0!==e&&(this._g3=0<e?1:-1);d=h?this._b3:this._c3;a=h?a:e;f?g>this._n3?g=this._h3+a*this._n1:g<this._o3&&(g=this._h3+a*this._n1):this._z||(0>=this.currSlideId&&
338150<d-this._d3&&(g=this._h3+a*this._n1),this.currSlideId>=this.numSlides-1&&0>d-this._d3&&(g=this._h3+a*this._n1));this._h3=g;200<c-this._j3&&(this._j3=c,this._v=d);f?this._q3(this._h3):this._l&&this._p3(this._h3)}},_x2:function(b,f){var c=this,a,e="touchmove"===b.type;if(!c._s2||e){if(e){if(c._r3)return;var g=b.originalEvent.touches;if(g){if(1<g.length)return;a=g[0]}else return}else a=b,c.pointerEnabled&&(a=a.originalEvent);c._a3||(c._e&&(f?c._s3:c._p1).css(c._g+c._u1,"0s"),function h(){c._l2&&(c._t3=
33816requestAnimationFrame(h),c._u3&&c._k3(c._u3,f))}());if(c._l3)b.preventDefault(),c._m3=(new Date).getTime(),c._u3=a;else if(g=f?c._e3:c._h,a=Math.abs(a.pageX-c._b3)-Math.abs(a.pageY-c._c3)-(g?-7:7),7<a){if(g)b.preventDefault(),c._z2="x";else if(e){c._v3(b);return}c._l3=!0}else if(-7>a){if(!g)b.preventDefault(),c._z2="y";else if(e){c._v3(b);return}c._l3=!0}}},_v3:function(b,f){this._r3=!0;this._a3=this._l2=!1;this._y2(b)},_y2:function(b,f){function c(a){return 100>a?100:500<a?500:a}function a(a,b){if(e._l||
33817f)h=(-e._u-e._d1)*e._w,k=Math.abs(e._p-h),e._c=k/b,a&&(e._c+=250),e._c=c(e._c),e._x3(h,!1)}var e=this,g,d,h,k;g=-1<b.type.indexOf("touch");if(!e._s2||g)if(e._s2=!1,e.ev.trigger("rsDragRelease"),e._u3=null,e._l2=!1,e._r3=!1,e._l3=!1,e._m3=0,cancelAnimationFrame(e._t3),e._a3&&(f?e._q3(e._h3):e._l&&e._p3(e._h3)),e._b.off(e._k1).off(e._l1),g&&e._e1.off(e._m1),e._i1(),!e._a3&&!e._v2&&f&&e._w3){var l=n(b.target).closest(".rsNavItem");l.length&&e.goTo(l.index())}else{d=f?e._e3:e._h;if(!e._a3||"y"===e._z2&&
33818d||"x"===e._z2&&!d)if(!f&&e._t2){e._t2=!1;if(e.st.navigateByClick){e._i2(e.pointerEnabled?b.originalEvent:b);e.dragSuccess=!0;return}e.dragSuccess=!0}else{e._t2=!1;e.dragSuccess=!1;return}else e.dragSuccess=!0;e._t2=!1;e._z2="";var r=e.st.minSlideOffset;g=g?b.originalEvent.changedTouches[0]:e.pointerEnabled?b.originalEvent:b;var m=d?g.pageX:g.pageY,p=e._d3;g=e._v;var q=e.currSlideId,s=e.numSlides,v=d?e._f3:e._g3,u=e._z;Math.abs(m-p);g=m-g;d=(new Date).getTime()-e._j3;d=Math.abs(g)/d;if(0===v||1>=
33819s)a(!0,d);else{if(!u&&!f)if(0>=q){if(0<v){a(!0,d);return}}else if(q>=s-1&&0>v){a(!0,d);return}if(f){h=e._i3;if(h>e._n3)h=e._n3;else if(h<e._o3)h=e._o3;else{m=d*d/0.006;l=-e._i3;p=e._y3-e._z3+e._i3;0<g&&m>l?(l+=e._z3/(15/(m/d*0.003)),d=d*l/m,m=l):0>g&&m>p&&(p+=e._z3/(15/(m/d*0.003)),d=d*p/m,m=p);l=Math.max(Math.round(d/0.003),50);h+=m*(0>g?-1:1);if(h>e._n3){e._a4(h,l,!0,e._n3,200);return}if(h<e._o3){e._a4(h,l,!0,e._o3,200);return}}e._a4(h,l,!0)}else l=function(a){var b=Math.floor(a/e._w);a-b*e._w>
33820r&&b++;return b},p+r<m?0>v?a(!1,d):(l=l(m-p),e._m2(e.currSlideId-l,c(Math.abs(e._p-(-e._u-e._d1+l)*e._w)/d),!1,!0,!0)):p-r>m?0<v?a(!1,d):(l=l(p-m),e._m2(e.currSlideId+l,c(Math.abs(e._p-(-e._u-e._d1-l)*e._w)/d),!1,!0,!0)):a(!1,d)}}},_p3:function(b){b=this._p=b;this._e?this._p1.css(this._x1,this._y1+(this._h?b+this._z1+0:0+this._z1+b)+this._a2):this._p1.css(this._h?this._x1:this._w1,b)},updateSliderSize:function(b){var f,c;if(this.slider){if(this.st.autoScaleSlider){var a=this.st.autoScaleSliderWidth,
33821e=this.st.autoScaleSliderHeight;this.st.autoScaleHeight?(f=this.slider.width(),f!=this.width&&(this.slider.css("height",e/a*f),f=this.slider.width()),c=this.slider.height()):(c=this.slider.height(),c!=this.height&&(this.slider.css("width",a/e*c),c=this.slider.height()),f=this.slider.width())}else f=this.slider.width(),c=this.slider.height();if(b||f!=this.width||c!=this.height){this.width=f;this.height=c;this._b4=f;this._c4=c;this.ev.trigger("rsBeforeSizeSet");this.ev.trigger("rsAfterSizePropSet");
33822this._e1.css({width:this._b4,height:this._c4});this._w=(this._h?this._b4:this._c4)+this.st.slidesSpacing;this._d4=this.st.imageScalePadding;
33822for(f=0;f<this.slides.length;f++)b=this.slides[f],b.positionSet=!1,b&&b.images&&b.isLoaded&&(b.isRendered=!1,this._q2(b));if(this._e4)for(f=0;f<this._e4.length;f++)b=this._e4[f],b.holder.css(this._i,(b.id+this._d1)*this._w);this._n2();this._l&&(this._e&&this._p1.css(this._g+"transition-duration","0s"),this._p3((-this._u-this._d1)*this._w));this.ev.trigger("rsOnUpdateNav")}this._j2=
33823this._e1.offset();this._j2=this._j2[this._i]}},appendSlide:function(b,f){var c=this._s(b);if(isNaN(f)||f>this.numSlides)f=this.numSlides;this.slides.splice(f,0,c);this.slidesJQ.splice(f,0,n('<div style="'+(this._l?"position:absolute;":this._n)+'" class="rsSlide"></div>'));f<=this.currSlideId&&this.currSlideId++;this.ev.trigger("rsOnAppendSlide",[c,f]);this._f4(f);f===this.currSlideId&&this.ev.trigger("rsAfterSlideChange")},removeSlide:function(b){var f=this.slides[b];f&&(f.holder&&f.holder.remove(),
33824b<this.currSlideId&&this.currSlideId--,this.slides.splice(b,1),this.slidesJQ.splice(b,1),this.ev.trigger("rsOnRemoveSlide",[b]),this._f4(b),b===this.currSlideId&&this.ev.trigger("rsAfterSlideChange"))},_f4:function(b){var f=this;b=f.numSlides;b=0>=f._u?0:Math.floor(f._u/b);f.numSlides=f.slides.length;0===f.numSlides?(f.currSlideId=f._d1=f._u=0,f.currSlide=f._g4=null):f._u=b*f.numSlides+f.currSlideId;for(b=0;b<f.numSlides;b++)f.slides[b].id=b;f.currSlide=f.slides[f.currSlideId];f._r1=f.slidesJQ[f.currSlideId];
33825f.currSlideId>=f.numSlides?f.goTo(f.numSlides-1):0>f.currSlideId&&f.goTo(0);f._t();f._l&&f._p1.css(f._g+f._u1,"0ms");f._h4&&clearTimeout(f._h4);f._h4=setTimeout(function(){f._l&&f._p3((-f._u-f._d1)*f._w);f._n2();f._l||f._r1.css({display:"block",opacity:1})},14);f.ev.trigger("rsOnUpdateNav")},_i1:function(){this._f1&&this._l&&(this._g1?this._e1.css("cursor",this._g1):(this._e1.removeClass("grabbing-cursor"),this._e1.addClass("grab-cursor")))},_w2:function(){this._f1&&this._l&&(this._h1?this._e1.css("cursor",
33826this._h1):(this._e1.removeClass("grab-cursor"),this._e1.addClass("grabbing-cursor")))},next:function(b){this._m2("next",this.st.transitionSpeed,!0,!b)},prev:function(b){this._m2("prev",this.st.transitionSpeed,!0,!b)},_m2:function(b,f,c,a,e){var g=this,d,h,k;g.ev.trigger("rsBeforeMove",[b,a]);k="next"===b?g.currSlideId+1:"prev"===b?g.currSlideId-1:b=parseInt(b,10);if(!g._z){if(0>k){g._i4("left",!a);return}if(k>=g.numSlides){g._i4("right",!a);return}}g._r2&&(g._u2(!0),c=!1);h=k-g.currSlideId;k=g._o2=
33827g.currSlideId;var l=g.currSlideId+h;a=g._u;var n;g._z?(l=g._n2(!1,l),a+=h):a=l;g._o=l;g._g4=g.slidesJQ[g.currSlideId];g._u=a;g.currSlideId=g._o;g.currSlide=g.slides[g.currSlideId];g._r1=g.slidesJQ[g.currSlideId];var l=g.st.slidesDiff,m=Boolean(0<h);h=Math.abs(h);var p=Math.floor(k/g._y),q=Math.floor((k+(m?l:-l))/g._y),p=(m?Math.max(p,q):Math.min(p,q))*g._y+(m?g._y-1:0);p>g.numSlides-1?p=g.numSlides-1:0>p&&(p=0);k=m?p-k:k-p;k>g._y&&(k=g._y);if(h>k+l)for(g._d1+=(h-(k+l))*(m?-1:1),f*=1.4,k=0;k<g.numSlides;k++)g.slides[k].positionSet=
33828!1;g._c=f;g._n2(!0);e||(n=!0);d=(-a-g._d1)*g._w;n?setTimeout(function(){g._j4=!1;g._x3(d,b,!1,c);g.ev.trigger("rsOnUpdateNav")},0):(g._x3(d,b,!1,c),g.ev.trigger("rsOnUpdateNav"))},_f2:function(){this.st.arrowsNav&&(1>=this.numSlides?(this._c2.css("display","none"),this._d2.css("display","none")):(this._c2.css("display","block"),this._d2.css("display","block"),this._z||this.st.loopRewind||(0===this.currSlideId?this._c2.addClass("rsArrowDisabled"):this._c2.removeClass("rsArrowDisabled"),this.currSlideId===
33829this.numSlides-1?this._d2.addClass("rsArrowDisabled"):this._d2.removeClass("rsArrowDisabled"))))},_x3:function(b,f,c,a,e){function g(){var a;h&&(a=h.data("rsTimeout"))&&(h!==k&&h.css({opacity:0,display:"none",zIndex:0}),clearTimeout(a),h.data("rsTimeout",""));if(a=k.data("rsTimeout"))clearTimeout(a),k.data("rsTimeout","")}var d=this,h,k,l={};isNaN(d._c)&&(d._c=400);d._p=d._h3=b;d.ev.trigger("rsBeforeAnimStart");d._e?d._l?(d._c=parseInt(d._c,10),c=d._g+d._v1,l[d._g+d._u1]=d._c+"ms",l[c]=a?n.rsCSS3Easing[d.st.easeInOut]:
33830n.rsCSS3Easing[d.st.easeOut],d._p1.css(l),a||!d.hasTouch?setTimeout(function(){d._p3(b)},5):d._p3(b)):(d._c=d.st.transitionSpeed,h=d._g4,k=d._r1,k.data("rsTimeout")&&k.css("opacity",0),g(),h&&h.data("rsTimeout",setTimeout(function(){l[d._g+d._u1]="0ms";l.zIndex=0;l.display="none";h.data("rsTimeout","");h.css(l);setTimeout(function(){h.css("opacity",0)},16)},d._c+60)),l.display="block",l.zIndex=d._m,l.opacity=0,l[d._g+d._u1]="0ms",l[d._g+d._v1]=n.rsCSS3Easing[d.st.easeInOut],k.css(l),k.data("rsTimeout",
33831setTimeout(function(){k.css(d._g+d._u1,d._c+"ms");k.data("rsTimeout",setTimeout(function(){k.css("opacity",1);k.data("rsTimeout","")},20))},20))):d._l?(l[d._h?d._x1:d._w1]=b+"px",d._p1.animate(l,d._c,a?d.st.easeInOut:d.st.easeOut)):(h=d._g4,k=d._r1,k.stop(!0,!0).css({opacity:0,display:"block",zIndex:d._m}),d._c=d.st.transitionSpeed,k.animate({opacity:1},d._c,d.st.easeInOut),g(),h&&h.data("rsTimeout",setTimeout(function(){h.stop(!0,!0).css({opacity:0,display:"none",zIndex:0})},d._c+60)));d._r2=!0;
33832d.loadingTimeout&&clearTimeout(d.loadingTimeout);d.loadingTimeout=e?setTimeout(function(){d.loadingTimeout=null;e.call()},d._c+60):setTimeout(function(){d.loadingTimeout=null;d._k4(f)},d._c+60)},_u2:function(b){this._r2=!1;clearTimeout(this.loadingTimeout);if(this._l)if(!this._e)this._p1.stop(!0),this._p=parseInt(this._p1.css(this._x1),10);else{if(!b){b=this._p;var f=this._h3=this._l4();this._p1.css(this._g+this._u1,"0ms");b!==f&&this._p3(f)}}else 20<this._m?this._m=10:this._m++},_l4:function(){var b=
33833window.getComputedStyle(this._p1.get(0),null).getPropertyValue(this._g+"transform").replace(/^matrix\(/i,"").split(/, |\)$/g),f=0===b[0].indexOf("matrix3d");return parseInt(b[this._h?f?12:4:f?13:5],10)},_m4:function(b,f){return this._e?this._y1+(f?b+this._z1+0:0+this._z1+b)+this._a2:b},_k4:function(b){this._l||(this._r1.css("z-index",0),this._m=10);this._r2=!1;this.staticSlideId=this.currSlideId;this._n2();this._n4=!1;this.ev.trigger("rsAfterSlideChange")},_i4:function(b,f){var c=this,a=(-c._u-c._d1)*
33834c._w;if(0!==c.numSlides&&!c._r2)if(c.st.loopRewind)c.goTo("left"===b?c.numSlides-1:0,f);else if(c._l){c._c=200;var e=function(){c._r2=!1};c._x3(a+("left"===b?30:-30),"",!1,!0,function(){c._r2=!1;c._x3(a,"",!1,!0,e)})}}
33834,_q2:function(b,f){if(!b.isRendered){var c=b.content,a="rsMainSlideImage",e,g=this.st.imageAlignCenter,d=this.st.imageScaleMode,h;b.videoURL&&(a="rsVideoContainer","fill"!==d?e=!0:(h=c,h.hasClass(a)||(h=h.find("."+a)),h.css({width:"100%",height:"100%"}),a="rsMainSlideImage"));c.hasClass(a)||
33835(c=c.find("."+a));if(c){var k=b.iW,l=b.iH;b.isRendered=!0;if("none"!==d||g){a="fill"!==d?this._d4:0;h=this._b4-2*a;var n=this._c4-2*a,m,p,q={};"fit-if-smaller"===d&&(k>h||l>n)&&(d="fit");if("fill"===d||"fit"===d)m=h/k,p=n/l,m="fill"==d?m>p?m:p:"fit"==d?m<p?m:p:1,k=Math.ceil(k*m,10),l=Math.ceil(l*m,10);"none"!==d&&(q.width=k,q.height=l,e&&c.find(".rsImg").css({width:"100%",height:"100%"}));g&&(q.marginLeft=Math.floor((h-k)/2)+a,q.marginTop=Math.floor((n-l)/2)+a);c.css(q)}}}}};n.rsProto=u.prototype;
33836n.fn.royalSlider=function(b){var f=arguments;return this.each(function(){var c=n(this);if("object"!==typeof b&&b){if((c=c.data("royalSlider"))&&c[b])return c[b].apply(c,Array.prototype.slice.call(f,1))}else c.data("royalSlider")||c.data("royalSlider",new u(c,b))})};n.fn.royalSlider.defaults={slidesSpacing:8,startSlideId:0,loop:!1,loopRewind:!1,numImagesToPreload:4,fadeinLoadedSlide:!0,slidesOrientation:"horizontal",transitionType:"move",transitionSpeed:600,controlNavigation:"bullets",controlsInside:!0,
33837arrowsNav:!0,arrowsNavAutoHide:!0,navigateByClick:!0,randomizeSlides:!1,sliderDrag:!0,sliderTouch:!0,keyboardNavEnabled:!1,fadeInAfterLoaded:!0,allowCSS3:!0,allowCSS3OnWebkit:!0,addActiveClass:!1,autoHeight:!1,easeOut:"easeOutSine",easeInOut:"easeInOutSine",minSlideOffset:10,imageScaleMode:"fit-if-smaller",imageAlignCenter:!0,imageScalePadding:4,usePreloader:!0,autoScaleSlider:!1,autoScaleSliderWidth:800,autoScaleSliderHeight:400,autoScaleHeight:!0,arrowsNavHideOnTouch:!1,globalCaption:!1,slidesDiff:2};
33838n.rsCSS3Easing={easeOutSine:"cubic-bezier(0.390, 0.575, 0.565, 1.000)",easeInOutSine:"cubic-bezier(0.445, 0.050, 0.550, 0.950)"};n.extend(jQuery.easing,{easeInOutSine:function(b,f,c,a,e){return-a/2*(Math.cos(Math.PI*f/e)-1)+c},easeOutSine:function(b,f,c,a,e){return a*Math.sin(f/e*(Math.PI/2))+c},easeOutCubic:function(b,f,c,a,e){return a*((f=f/e-1)*f*f+1)+c}})})(jQuery,window);
33839// jquery.rs.active-class v1.0.1
33840(function(c){c.rsProto._o4=function(){var b,a=this;if(a.st.addActiveClass)a.ev.on("rsOnUpdateNav",function(){b&&clearTimeout(b);b=setTimeout(function(){a._g4&&a._g4.removeClass("rsActiveSlide");a._r1&&a._r1.addClass("rsActiveSlide");b=null},50)})};c.rsModules.activeClass=c.rsProto._o4})(jQuery);
33841// jquery.rs.animated-blocks v1.0.7
33842(function(l){l.extend(l.rsProto,{_p4:function(){function m(){var g=a.currSlide;if(a.currSlide&&a.currSlide.isLoaded&&a._t4!==g){if(0<a._s4.length){for(b=0;b<a._s4.length;b++)clearTimeout(a._s4[b]);a._s4=[]}if(0<a._r4.length){var f;for(b=0;b<a._r4.length;b++)if(f=a._r4[b])a._e?(f.block.css(a._g+a._u1,"0s"),f.block.css(f.css)):f.block.stop(!0).css(f.css),a._t4=null,g.animBlocksDisplayed=!1;a._r4=[]}g.animBlocks&&(g.animBlocksDisplayed=!0,a._t4=g,a._u4(g.animBlocks))}}var a=this,b;a._q4={fadeEffect:!0,
33843moveEffect:"top",moveOffset:20,speed:400,easing:"easeOutSine",delay:200};a.st.block=l.extend({},a._q4,a.st.block);a._r4=[];a._s4=[];a.ev.on("rsAfterInit",function(){m()});a.ev.on("rsBeforeParseNode",function(a,b,d){b=l(b);d.animBlocks=b.find(".rsABlock").css("display","none");d.animBlocks.length||(b.hasClass("rsABlock")?d.animBlocks=b.css("display","none"):d.animBlocks=!1)});a.ev.on("rsAfterContentSet",function(b,f){f.id===a.slides[a.currSlideId].id&&setTimeout(function(){m()},a.st.fadeinLoadedSlide?
33844300:0)});a.ev.on("rsAfterSlideChange",function(){m()})},_v4:function(l,a){setTimeout(function(){l.css(a)},6)},_u4:function(m){var a=this,b,g,f,d,h,e,n;a._s4=[];m.each(function(m){b=l(this);g={};f={};d=null;var c=b.attr("data-move-offset"),c=c?parseInt(c,10):a.st.block.moveOffset;if(0<c&&((e=b.data("move-effect"))?(e=e.toLowerCase(),"none"===e?e=!1:"left"!==e&&"top"!==e&&"bottom"!==e&&"right"!==e&&(e=a.st.block.moveEffect,"none"===e&&(e=!1))):e=a.st.block.moveEffect,e&&"none"!==e)){var p;p="right"===
33845e||"left"===e?!0:!1;var k;n=!1;a._e?(k=0,h=a._x1):(p?isNaN(parseInt(b.css("right"),10))?h="left":(h="right",n=!0):isNaN(parseInt(b.css("bottom"),10))?h="top":(h="bottom",n=!0),h="margin-"+h,n&&(c=-c),a._e?k=parseInt(b.css(h),10):(k=b.data("rs-start-move-prop"),void 0===k&&(k=parseInt(b.css(h),10),isNaN(k)&&(k=0),b.data("rs-start-move-prop",k))));f[h]=a._m4("top"===e||"left"===e?k-c:k+c,p);g[h]=a._m4(k,p)}c=b.attr("data-fade-effect");if(!c)c=a.st.block.fadeEffect;else if("none"===c.toLowerCase()||
33846"false"===c.toLowerCase())c=!1;c&&(f.opacity=0,g.opacity=1);if(c||e)d={}
33846,d.hasFade=Boolean(c),Boolean(e)&&(d.moveProp=h,d.hasMove=!0),d.speed=b.data("speed"),isNaN(d.speed)&&(d.speed=a.st.block.speed),d.easing=b.data("easing"),d.easing||(d.easing=a.st.block.easing),d.css3Easing=l.rsCSS3Easing[d.easing],d.delay=b.data("delay"),isNaN(d.delay)&&(d.delay=a.st.block.delay*m);c={};a._e&&(c[a._g+a._u1]="0ms");c.moveProp=g.moveProp;c.opacity=g.opacity;c.display="none";a._r4.push({block:b,css:c});a._v4(b,
33847f);a._s4.push(setTimeout(function(b,d,c,e){return function(){b.css("display","block");if(c){var g={};if(a._e){var f="";c.hasMove&&(f+=c.moveProp);c.hasFade&&(c.hasMove&&(f+=", "),f+="opacity");g[a._g+a._t1]=f;g[a._g+a._u1]=c.speed+"ms";g[a._g+a._v1]=c.css3Easing;b.css(g);setTimeout(function(){b.css(d)},24)}else setTimeout(function(){b.animate(d,c.speed,c.easing)},16)}delete a._s4[e]}}(b,g,d,m),6>=d.delay?12:d.delay))})}});l.rsModules.animatedBlocks=l.rsProto._p4})(jQuery);
33848// jquery.rs.auto-height v1.0.3
33849(function(b){b.extend(b.rsProto,{_w4:function(){var a=this;if(a.st.autoHeight){var b,c,e,f=!0,d=function(d){e=a.slides[a.currSlideId];(b=e.holder)&&(c=b.height())&&void 0!==c&&c>(a.st.minAutoHeight||30)&&(a._c4=c,a._e||!d?a._e1.css("height",c):a._e1.stop(!0,!0).animate({height:c},a.st.transitionSpeed),a.ev.trigger("rsAutoHeightChange",c),f&&(a._e&&setTimeout(function(){a._e1.css(a._g+"transition","height "+a.st.transitionSpeed+"ms ease-in-out")},16),f=!1))};a.ev.on("rsMaybeSizeReady.rsAutoHeight",
33850function(a,b){e===b&&d()});a.ev.on("rsAfterContentSet.rsAutoHeight",function(a,b){e===b&&d()});a.slider.addClass("rsAutoHeight");a.ev.one("rsAfterInit",function(){setTimeout(function(){d(!1);setTimeout(function(){a.slider.append('<div style="clear:both; float: none;"></div>')},16)},16)});a.ev.on("rsBeforeAnimStart",function(){d(!0)});a.ev.on("rsBeforeSizeSet",function(){setTimeout(function(){d(!1)},16)})}}});b.rsModules.autoHeight=b.rsProto._w4})(jQuery);
33851// jquery.rs.autoplay v1.0.5
33852(function(b){b.extend(b.rsProto,{_x4:function(){var a=this,d;
33852a._y4={enabled:!1,stopAtAction:!0,pauseOnHover:!0,delay:2E3};!a.st.autoPlay&&a.st.autoplay&&(a.st.autoPlay=a.st.autoplay);a.st.autoPlay=b.extend({},a._y4,a.st.autoPlay);a.st.autoPlay.enabled&&(a.ev.on("rsBeforeParseNode",function(a,c,f){c=b(c);if(d=c.attr("data-rsDelay"))f.customDelay=parseInt(d,10)}),a.ev.one("rsAfterInit",function(){a._z4()}),a.ev.on("rsBeforeDestroy",function(){a.stopAutoPlay();a.slider.off("mouseenter mouseleave");b(window).off("blur"+
33853a.ns+" focus"+a.ns)}))},_z4:function(){var a=this;a.startAutoPlay();a.ev.on("rsAfterContentSet",function(b,e){a._l2||a._r2||!a._a5||e!==a.currSlide||a._b5()});a.ev.on("rsDragRelease",function(){a._a5&&a._c5&&(a._c5=!1,a._b5())});a.ev.on("rsAfterSlideChange",function(){a._a5&&a._c5&&(a._c5=!1,a.currSlide.isLoaded&&a._b5())});a.ev.on("rsDragStart",function(){a._a5&&(a.st.autoPlay.stopAtAction?a.stopAutoPlay():(a._c5=!0,a._d5()))});a.ev.on("rsBeforeMove",function(b,e,c){a._a5&&(c&&a.st.autoPlay.stopAtAction?
33854a.stopAutoPlay():(a._c5=!0,a._d5()))});a._e5=!1;a.ev.on("rsVideoStop",function(){a._a5&&(a._e5=!1,a._b5())});a.ev.on("rsVideoPlay",function(){a._a5&&(a._c5=!1,a._d5(),a._e5=!0)});b(window).on("blur"+a.ns,function(){a._a5&&(a._c5=!0,a._d5())}).on("focus"+a.ns,function(){a._a5&&a._c5&&(a._c5=!1,a._b5())});a.st.autoPlay.pauseOnHover&&(a._f5=!1,a.slider.hover(function(){a._a5&&(a._c5=!1,a._d5(),a._f5=!0)},function(){a._a5&&(a._f5=!1,a._b5())}))},toggleAutoPlay:function(){this._a5?this.stopAutoPlay():
33855this.startAutoPlay()},startAutoPlay:function(){this._a5=!0;this.currSlide.isLoaded&&this._b5()},stopAutoPlay:function(){this._e5=this._f5=this._c5=this._a5=!1;this._d5()},_b5:function(){var a=this;a._f5||a._e5||(a._g5=!0,a._h5&&clearTimeout(a._h5),a._h5=setTimeout(function(){var b;a._z||a.st.loopRewind||(b=!0,a.st.loopRewind=!0);a.next(!0);b&&(a.st.loopRewind=!1)},a.currSlide.customDelay?a.currSlide.customDelay:a.st.autoPlay.delay))},_d5:function(){this._f5||this._e5||(this._g5=!1,this._h5&&(clearTimeout(this._h5),
33856this._h5=null))}});b.rsModules.autoplay=b.rsProto._x4})(jQuery);
33857// jquery.rs.bullets v1.0.1
33858(function(c){c.extend(c.rsProto,{_i5:function(){var a=this;"bullets"===a.st.controlNavigation&&(a.ev.one("rsAfterPropsSetup",function(){a._j5=!0;a.slider.addClass("rsWithBullets");for(var b='<div class="rsNav rsBullets">',e=0;e<a.numSlides;e++)b+='<div class="rsNavItem rsBullet"><span></span></div>';a._k5=b=c(b+"</div>");a._l5=b.appendTo(a.slider).children();a._k5.on("click.rs",".rsNavItem",function(b){a._m5||a.goTo(c(this).index())})}),a.ev.on("rsOnAppendSlide",function(b,c,d){d>=a.numSlides?a._k5.append('<div class="rsNavItem rsBullet"><span></span></div>'):
33859a._l5.eq(d).before('<div class="rsNavItem rsBullet"><span></span></div>');a._l5=a._k5.children()}),a.ev.on("rsOnRemoveSlide",function(b,c){var d=a._l5.eq(c);d&&d.length&&(d.remove(),a._l5=a._k5.children())}),a.ev.on("rsOnUpdateNav",function(){var b=a.currSlideId;a._n5&&a._n5.removeClass("rsNavSelected");b=a._l5.eq(b);b.addClass("rsNavSelected");a._n5=b}))}});c.rsModules.bullets=c.rsProto._i5})(jQuery);
33860// jquery.rs.deeplinking v1.0.6 + jQuery hashchange plugin v1.3 Copyright (c) 2010 Ben Alman
33861(function(d){d.extend(d.rsProto,{_o5:function(){var a=this,l,g,f;a._p5={enabled:!1,change:!1,prefix:""};a.st.deeplinking=d.extend({},a._p5,a.st.deeplinking);if(a.st.deeplinking.enabled){var k=a.st.deeplinking.change,c=a.st.deeplinking.prefix,e="#"+c,h=function(){var b=window.location.hash;return b&&0<b.indexOf(c)&&(b=parseInt(b.substring(e.length),10),0<=b)?b-1:-1},m=h();-1!==m&&(a.st.startSlideId=m);k&&(d(window).on("hashchange"+a.ns,function(b){l||(b=h(),0>b||(b>a.numSlides-1&&(b=a.numSlides-1),
33862a.goTo(b)))}),a.ev.on("rsBeforeAnimStart",function(){g&&clearTimeout(g);f&&clearTimeout(f)}),a.ev.on("rsAfterSlideChange",function(){g&&clearTimeout(g);f&&clearTimeout(f);f=setTimeout(function(){l=!0;window.location.replace((""+window.location).split("#")[0]+e+(a.currSlideId+1));g=setTimeout(function(){l=!1;g=null},60)},400)}));a.ev.on("rsBeforeDestroy",function(){g=f=null;k&&d(window).off("hashchange"+a.ns)})}}});d.rsModules.deeplinking=d.rsProto._o5})(jQuery);
33863(function(d,a,l){function g(b){b=b||location.href;return"#"+b.replace(/^[^#]*#?(.*)$/,"$1")}"$:nomunge";var f="hashchange",k=document,c,e=d.event.special,h=k.documentMode,m="on"+f in a&&(h===l||7<h);d.fn[f]=function(b){return b?this.bind(f,b):this.trigger(f)};d.fn[f].delay=50;e[f]=d.extend(e[f],{setup:function(){if(m)return!1;d(c.start)},teardown:function(){if(m)return!1;
33863d(c.stop)}});c=function(){function b(){var c=g(),n=r(h);c!==h?(p(h=c,n),d(a).trigger(f)):n!==h&&(location.href=location.href.replace(/#.*/,
33864"")+n);e=setTimeout(b,d.fn[f].delay)}var c={},e,h=g(),q=function(b){return b},p=q,r=q;c.start=function(){e||b()};c.stop=function(){e&&clearTimeout(e);e=l};a.attachEvent&&!a.addEventListener&&!m&&function(){var a,e;c.start=function(){a||(e=(e=d.fn[f].src)&&e+g(),a=d('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){e||p(g());b()}).attr("src",e||"javascript:0").insertAfter("body")[0].contentWindow,k.onpropertychange=function(){try{"title"===event.propertyName&&(a.document.title=
33865k.title)}catch(b){}})};c.stop=q;r=function(){return g(a.location.href)};p=function(b,e){var c=a.document,g=d.fn[f].domain;b!==e&&(c.title=k.title,c.open(),g&&c.write('<script>document.domain="'+g+'"\x3c/script>'),c.close(),a.location.hash=b)}}();return c}()})(jQuery,this);
33866// jquery.rs.fullscreen v1.0.6
33867(function(c){c.extend(c.rsProto,{_q5:function(){var a=this;a._r5={enabled:!1,keyboardNav:!0,buttonFS:!0,nativeFS:!1,doubleTap:!0};a.st.fullscreen=c.extend({},a._r5,a.st.fullscreen);if(a.st.fullscreen.enabled)a.ev.one("rsBeforeSizeSet",function(){a._s5()})},_s5:function(){var a=this;a._t5=!a.st.keyboardNavEnabled&&a.st.fullscreen.keyboardNav;
33867if(a.st.fullscreen.nativeFS){var b={supportsFullScreen:!1,isFullScreen:function(){return!1},requestFullScreen:function(){},cancelFullScreen:function(){},fullScreenEventName:"",
33868prefix:""},d=["webkit","moz","o","ms","khtml"];if("undefined"!=typeof document.cancelFullScreen)b.supportsFullScreen=!0;else for(var e=0,f=d.length;e<f;e++)if(b.prefix=d[e],"undefined"!=typeof document[b.prefix+"CancelFullScreen"]){b.supportsFullScreen=!0;break}b.supportsFullScreen?(a.nativeFS=!0,b.fullScreenEventName=b.prefix+"fullscreenchange"+a.ns,b.isFullScreen=function(){switch(this.prefix){case "":return document.fullScreen;case "webkit":return document.webkitIsFullScreen;default:return document[this.prefix+
33869"FullScreen"]}},b.requestFullScreen=function(a){return""===this.prefix?a.requestFullScreen():a[this.prefix+"RequestFullScreen"]()},b.cancelFullScreen=function(a){return""===this.prefix?document.cancelFullScreen():document[this.prefix+"CancelFullScreen"]()},a._u5=b):a._u5=!1}a.st.fullscreen.buttonFS&&(a._v5=c('<div class="rsFullscreenBtn"><div class="rsFullscreenIcn"></div></div>').appendTo(a._o1).on("click.rs",function(){a.isFullscreen?a.exitFullscreen():a.enterFullscreen()}))},enterFullscreen:function(a){var b=
33870this;if(b._u5)if(a)b._u5.requestFullScreen(c("html")[0]);else{b._b.on(b._u5.fullScreenEventName,function(a){b._u5.isFullScreen()?b.enterFullscreen(!0):b.exitFullscreen(!0)});b._u5.requestFullScreen(c("html")[0]);return}if(!b._w5){b._w5=!0;b._b.on("keyup"+b.ns+"fullscreen",function(a){27===a.keyCode&&b.exitFullscreen()});b._t5&&b._b2();a=c(window);b._x5=a.scrollTop();b._y5=a.scrollLeft();b._z5=c("html").attr("style");b._a6=c("body").attr("style");b._b6=b.slider.attr("style");c("body, html").css({overflow:"hidden",
33871height:"100%",width:"100%",margin:"0",padding:"0"});b.slider.addClass("rsFullscreen");var d;for(d=0;d<b.numSlides;d++)a=b.slides[d],a.isRendered=!1,a.bigImage&&(a.isBig=!0,a.isMedLoaded=a.isLoaded,a.isMedLoading=a.isLoading,a.medImage=a.image,a.medIW=a.iW,a.medIH=a.iH,a.slideId=-99,a.bigImage!==a.medImage&&(a.sizeType="big"),a.isLoaded=a.isBigLoaded,a.isLoading=!1,a.image=a.bigImage,a.images[0]=a.bigImage,a.iW=a.bigIW,a.iH=a.bigIH,a.isAppended=a.contentAdded=!1,b._c6(a));b.isFullscreen=!0;b._w5=!1;
33872b.updateSliderSize();b.ev.trigger("rsEnterFullscreen")}},exitFullscreen:function(a){var b=this;if(b._u5){if(!a){b._u5.cancelFullScreen(c("html")[0]);return}b._b.off(b._u5.fullScreenEventName)}if(!b._w5){b._w5=!0;b._b.off("keyup"+b.ns+"fullscreen");b._t5&&b._b.off("keydown"+b.ns);c("html").attr("style",b._z5||"");c("body").attr("style",b._a6||"");var d;for(d=0;d<b.numSlides;d++)a=b.slides[d],a.isRendered=!1,a.bigImage&&(a.isBig=!1,a.slideId=-99,a.isBigLoaded=a.isLoaded,a.isBigLoading=a.isLoading,a.bigImage=
33873a.image,a.bigIW=a.iW,a.bigIH=a.iH,a.isLoaded=a.isMedLoaded,a.isLoading=!1,a.image=a.medImage,a.images[0]=a.medImage,a.iW=a.medIW,a.iH=a.medIH,a.isAppended=a.contentAdded=!1,b._c6(a,!0),a.bigImage!==a.medImage&&(a.sizeType="med"));b.isFullscreen=!1;a=c(window);a.scrollTop(b._x5);a.scrollLeft(b._y5);b._w5=!1;b.slider.removeClass("rsFullscreen");b.updateSliderSize();setTimeout(function(){b.updateSliderSize()},1);b.ev.trigger("rsExitFullscreen")}},_c6:function(a,b){var d=a.isLoaded||a.isLoading?'<img class="rsImg rsMainSlideImage" src="'+
33874a.image+'"/>':'<a class="rsImg rsMainSlideImage" href="'+a.image+'"></a>';a.content.hasClass("rsImg")?a.content=c(d):a.content.find(".rsImg").eq(0).replaceWith(d);a.isLoaded||a.isLoading||!a.holder||a.holder.html(a.content)}});c.rsModules.fullscreen=c.rsProto._q5})(jQuery);
33875// jquery.rs.global-caption v1.0
33876(function(b){b.extend(b.rsProto,{_d6:function(){var a=this;a.st.globalCaption&&(a.ev.on("rsAfterInit",function(){a.globalCaption=b('<div class="rsGCaption"></div>').appendTo(a.st.globalCaptionInside?a._e1:a.slider);a.globalCaption.html(a.currSlide.caption)}),a.ev.on("rsBeforeAnimStart",function(){a.globalCaption.html(a.currSlide.caption)}))}});b.rsModules.globalCaption=b.rsProto._d6})(jQuery);
33877// jquery.rs.nav-auto-hide v1.0
33878(function(b){b.extend(b.rsProto,{_e6:function(){var a=this;if(a.st.navAutoHide&&!a.hasTouch)a.ev.one("rsAfterInit",function(){if(a._k5){a._k5.addClass("rsHidden");var b=a.slider;b.one("mousemove.controlnav",function(){a._k5.removeClass("rsHidden")});b.hover(function(){a._k5.removeClass("rsHidden")},function(){a._k5.addClass("rsHidden")})}})}});b.rsModules.autoHideNav=b.rsProto._e6})(jQuery);
33879// jquery.rs.tabs v1.0.2
33880(function(e){e.extend(e.rsProto,{_f6:function(){var a=this;"tabs"===a.st.controlNavigation&&(a.ev.on("rsBeforeParseNode",function(a,d,b){d=e(d);b.thumbnail=d.find(".rsTmb").remove();b.thumbnail.length?b.thumbnail=e(document.createElement("div")).append(b.thumbnail).html():(b.thumbnail=d.attr("data-rsTmb"),b.thumbnail||(b.thumbnail=d.find(".rsImg").attr("data-rsTmb")),b.thumbnail=b.thumbnail?'<img src="'+b.thumbnail+'"/>':"")}),a.ev.one("rsAfterPropsSetup",function(){a._g6()}),a.ev.on("rsOnAppendSlide",
33881function(c,d,b){b>=a.numSlides?a._k5.append('<div class="rsNavItem rsTab">'+d.thumbnail+"</div>"):a._l5.eq(b).before('<div class="rsNavItem rsTab">'+item.thumbnail+"</div>");a._l5=a._k5.children()}),a.ev.on("rsOnRemoveSlide",function(c,d){var b=a._l5.eq(d);b&&(b.remove(),a._l5=a._k5.children())}),a.ev.on("rsOnUpdateNav",function(){var c=a.currSlideId;a._n5&&a._n5.removeClass("rsNavSelected");c=a._l5.eq(c);c.addClass("rsNavSelected");a._n5=c}))},_g6:function(){var a=this,c;a._j5=!0;c='<div class="rsNav rsTabs">';
33882for(var d=0;d<a.numSlides;d++)c+='<div class="rsNavItem rsTab">'+a.slides[d].thumbnail+"</div>";c=e(c+"</div>");a._k5=c;a._l5=c.children(".rsNavItem");a.slider.append(c);a._k5.click(function(b){b=e(b.target).closest(".rsNavItem");b.length&&a.goTo(b.index())})}});e.rsModules.tabs=e.rsProto._f6})(jQuery);
33883// jquery.rs.thumbnails v1.0.7
33884(function(f){f.extend(f.rsProto,{_h6:function(){var a=this;"thumbnails"===a.st.controlNavigation&&(a._i6={drag:!0,touch:!0,orientation:"horizontal",navigation:!0,arrows:!0,arrowLeft:null,arrowRight:null,spacing:4,arrowsAutoHide:!1,appendSpan:!1,transitionSpeed:600,autoCenter:!0,fitInViewport:!0,firstMargin:!0,paddingTop:0,paddingBottom:0},a.st.thumbs=f.extend({},a._i6,a.st.thumbs),a._j6=!0,!1===a.st.thumbs.firstMargin?a.st.thumbs.firstMargin=0:!0===a.st.thumbs.firstMargin&&(a.st.thumbs.firstMargin=
33885a.st.thumbs.spacing),a.ev.on("rsBeforeParseNode",function(a,b,c){b=f(b);c.thumbnail=b.find(".rsTmb").remove();c.thumbnail.length?c.thumbnail=f(document.createElement("div")).append(c.thumbnail).html():(c.thumbnail=b.attr("data-rsTmb"),c.thumbnail||(c.thumbnail=b.find(".rsImg").attr("data-rsTmb")),c.thumbnail=c.thumbnail?'<img src="'+c.thumbnail+'"/>':"")}),a.ev.one("rsAfterPropsSetup",function(){a._k6()}),a._n5=null,a.ev.on("rsOnUpdateNav",function(){var e=f(a._l5[a.currSlideId]);e!==a._n5&&(a._n5&&
33886(a._n5.removeClass("rsNavSelected"),a._n5=null),a._l6&&a._m6(a.currSlideId),a._n5=e.addClass("rsNavSelected"))}),a.ev.on("rsOnAppendSlide",function(e,b,c){e="<div"+a._n6+' class="rsNavItem rsThumb">'+a._o6+b.thumbnail+"</div>";a._e&&a._s3.css(a._g+"transition-duration","0ms");c>=a.numSlides?a._s3.append(e):a._l5.eq(c).before(e);a._l5=a._s3.children();a.updateThumbsSize(!0)}),a.ev.on("rsOnRemoveSlide",function(e,b){var c=a._l5.eq(b);c&&(a._e&&a._s3.css(a._g+"transition-duration","0ms"),c.remove(),
33887a._l5=a._s3.children(),a.updateThumbsSize(!0))}))},_k6:function(){var a=this,e="rsThumbs",b=a.st.thumbs,c="",g,d,h=b.spacing;a._j5=!0;a._e3="vertical"===b.orientation?!1:!0;a._n6=g=h?' style="margin-'+(a._e3?"right":"bottom")+":"+h+'px;"':"";a._i3=0;a._p6=!1;a._m5=!1;a._l6=!1;a._q6=b.arrows&&b.navigation;d=a._e3?"Hor":"Ver";a.slider.addClass("rsWithThumbs rsWithThumbs"+d);c+='<div class="rsNav rsThumbs rsThumbs'+d+'"><div class="'+e+'Container">';a._o6=b.appendSpan?'<span class="thumbIco"></span>':
33888"";for(var k=0;k<a.numSlides;k++)d=a.slides[k],c+="<div"+g+' class="rsNavItem rsThumb">'+d.thumbnail+a._o6+"</div>";c=f(c+"</div></div>");g={};b.paddingTop&&(g[a._e3?"paddingTop":"paddingLeft"]=b.paddingTop);b.paddingBottom&&(g[a._e3?"paddingBottom":"paddingRight"]=b.paddingBottom);c.css(g);a._s3=f(c).find("."+e+"Container");a._q6&&(e+="Arrow",b.arrowLeft?a._r6=b.arrowLeft:(a._r6=f('<div class="'+e+" "+e+'Left"><div class="'+e+'Icn"></div></div>'),c.append(a._r6)),b.arrowRight?a._s6=b.arrowRight:
33889(a._s6=f('<div class="'+e+" "+e+'Right"><div class="'+e+'Icn"></div></div>'),c.append(a._s6)),a._r6.click(function(){var b=(Math.floor(a._i3/a._t6)+a._u6)*a._t6+a.st.thumbs.firstMargin;a._a4(b>a._n3?a._n3:b)}),a._s6.click(function(){var b=(Math.floor(a._i3/a._t6)-a._u6)*a._t6+a.st.thumbs.firstMargin;a._a4(b<a._o3?a._o3:b)}),b.arrowsAutoHide&&!a.hasTouch&&(a._r6.css("opacity",0),a._s6.css("opacity",0),c.one("mousemove.rsarrowshover",function(){a._l6&&(a._r6.css("opacity",1),a._s6.css("opacity",1))}),
33890c.hover(function(){a._l6&&(a._r6.css("opacity",1),a._s6.css("opacity",1))},function(){a._l6&&(a._r6.css("opacity",0),a._s6.css("opacity",0)
33890)})));a._k5=c;a._l5=a._s3.children();a.msEnabled&&a.st.thumbs.navigation&&a._s3.css("-ms-touch-action",a._e3?"pan-y":"pan-x");a.slider.append(c);a._w3=!0;a._v6=h;b.navigation&&a._e&&a._s3.css(a._g+"transition-property",a._g+"transform");a._k5.on("click.rs",".rsNavItem",function(b){a._m5||a.goTo(f(this).index())});a.ev.off("rsBeforeSizeSet.thumbs").on("rsBeforeSizeSet.thumbs",
33891function(){a._w6=a._e3?a._c4:a._b4;a.updateThumbsSize(!0)});a.ev.off("rsAutoHeightChange.thumbs").on("rsAutoHeightChange.thumbs",function(b,c){a.updateThumbsSize(!0,c)})},updateThumbsSize:function(a,e){var b=this,c=b._l5.first(),f={},d=b._l5.length;b._t6=(b._e3?c.outerWidth():c.outerHeight())+b._v6;b._y3=d*b._t6-b._v6;f[b._e3?"width":"height"]=b._y3+b._v6;b._z3=b._e3?b._k5.width():void 0!==e?e:b._k5.height();b._w3&&(b.isFullscreen||b.st.thumbs.fitInViewport)&&(b._e3?b._c4=b._w6-b._k5.outerHeight():
33892b._b4=b._w6-b._k5.outerWidth());b._z3&&(b._o3=-(b._y3-b._z3)-b.st.thumbs.firstMargin,b._n3=b.st.thumbs.firstMargin,b._u6=Math.floor(b._z3/b._t6),b._y3<b._z3?(b.st.thumbs.autoCenter&&b._q3((b._z3-b._y3)/2),b.st.thumbs.arrows&&b._r6&&(b._r6.addClass("rsThumbsArrowDisabled"),b._s6.addClass("rsThumbsArrowDisabled")),b._l6=!1,b._m5=!1,b._k5.off(b._j1)):b.st.thumbs.navigation&&!b._l6&&(b._l6=!0,!b.hasTouch&&b.st.thumbs.drag||b.hasTouch&&b.st.thumbs.touch)&&(b._m5=!0,b._k5.on(b._j1,function(a){b._g2(a,!0)})),
33893b._s3.css(f),a&&e&&b._m6(b.currSlideId,!0))},setThumbsOrientation:function(a,e){this._w3&&(this.st.thumbs.orientation=a,this._k5.remove(),this.slider.removeClass("rsWithThumbsHor rsWithThumbsVer"),this._k6(),this._k5.off(this._j1),e||this.updateSliderSize(!0))},_q3:function(a){this._i3=a;this._e?this._s3.css(this._x1,this._y1+(this._e3?a+this._z1+0:0+this._z1+a)+this._a2):this._s3.css(this._e3?this._x1:this._w1,a)},_a4:function(a,e,b,c,g){var d=this;if(d._l6){e||(e=d.st.thumbs.transitionSpeed);d._i3=
33894a;d._x6&&clearTimeout(d._x6);d._p6&&(d._e||d._s3.stop(),b=!0);var h={};d._p6=!0;d._e?(h[d._g+"transition-duration"]=e+"ms",h[d._g+"transition-timing-function"]=b?f.rsCSS3Easing[d.st.easeOut]:f.rsCSS3Easing[d.st.easeInOut],d._s3.css(h),d._q3(a)):(h[d._e3?d._x1:d._w1]=a+"px",d._s3.animate(h,e,b?"easeOutCubic":d.st.easeInOut));c&&(d._i3=c);d._y6();d._x6=setTimeout(function(){d._p6=!1;g&&(d._a4(c,g,!0),g=null)},e)}},_y6:function(){this._q6&&(this._i3===this._n3?this._r6.addClass("rsThumbsArrowDisabled"):
33895this._r6.removeClass("rsThumbsArrowDisabled"),this._i3===this._o3?this._s6.addClass("rsThumbsArrowDisabled"):this._s6.removeClass("rsThumbsArrowDisabled"))},_m6:function(a,e){var b=0,c,f=a*this._t6+2*this._t6-this._v6+this._n3,d=Math.floor(this._i3/this._t6);this._l6&&(this._j6&&(e=!0,this._j6=!1),f+this._i3>this._z3?(a===this.numSlides-1&&(b=1),d=-a+this._u6-2+b,c=d*this._t6+this._z3%this._t6+this._v6-this._n3):0!==a?(a-1)*this._t6<=-this._i3+this._n3&&a-1<=this.numSlides-this._u6&&(c=(-a+1)*this._t6+
33896this._n3):c=this._n3,c!==this._i3&&(b=void 0===c?this._i3:c,b>this._n3?this._q3(this._n3):b<this._o3?this._q3(this._o3):void 0!==c&&(e?this._q3(c):this._a4(c))),this._y6())}});f.rsModules.thumbnails=f.rsProto._h6})(jQuery);
33897// jquery.rs.video v1.1.3
33898(function(f){f.extend(f.rsProto,{_z6:function(){var a=this;a._a7={autoHideArrows:!0,autoHideControlNav:!1,autoHideBlocks:!1,autoHideCaption:!1,disableCSS3inFF:!0,youTubeCode:'<iframe src="https://www.youtube.com/embed/%id%?rel=1&showinfo=0&autoplay=1&wmode=transparent" frameborder="no"></iframe>',vimeoCode:'<iframe src="http://player.vimeo.com/video/%id%?byline=0&portrait=0&autoplay=1" frameborder="no" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'};a.st.video=f.extend({},a._a7,
33899a.st.video);a.ev.on("rsBeforeSizeSet",function(){a._b7&&setTimeout(function(){var b=a._r1,b=b.hasClass("rsVideoContainer")?b:b.find(".rsVideoContainer");
33899a._c7&&a._c7.css({width:b.width(),height:b.height()})},32)});var d=a._a.mozilla;a.ev.on("rsAfterParseNode",function(b,c,e){b=f(c);if(e.videoURL){a.st.video.disableCSS3inFF&&d&&(a._e=a._f=!1);c=f('<div class="rsVideoContainer"></div>');var g=f('<div class="rsBtnCenterer"><div class="rsPlayBtn"><div class="rsPlayBtnIcon"></div></div></div>');b.hasClass("rsImg")?
33900e.content=c.append(b).append(g):e.content.find(".rsImg").wrap(c).after(g)}});a.ev.on("rsAfterSlideChange",function(){a.stopVideo()})},toggleVideo:function(){return this._b7?this.stopVideo():this.playVideo()},playVideo:function(){var a=this;if(!a._b7){var d=a.currSlide;if(!d.videoURL)return!1;a._d7=d;var b=a._e7=d.content,d=d.videoURL,c,e;d.match(/youtu\.be/i)||d.match(/youtube\.com/i)?(e=/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/,(e=d.match(e))&&11==e[7].length&&
33901(c=e[7]),void 0!==c&&(a._c7=a.st.video.youTubeCode.replace("%id%",c))):d.match(/vimeo\.com/i)&&(e=/(www\.)?vimeo.com\/(\d+)($|\/)/,(e=d.match(e))&&(c=e[2]),void 0!==c&&(a._c7=a.st.video.vimeoCode.replace("%id%",c)));a.videoObj=f(a._c7);a.ev.trigger("rsOnCreateVideoElement",[d]);a.videoObj.length&&(a._c7=f('<div class="rsVideoFrameHolder"><div class="rsPreloader"></div><div class="rsCloseVideoBtn"><div class="rsCloseVideoIcn"></div></div></div>'),a._c7.find(".rsPreloader").after(a.videoObj),b=b.hasClass("rsVideoContainer")?
33902b:b.find(".rsVideoContainer"),a._c7.css({width:b.width(),height:b.height()}).find(".rsCloseVideoBtn").off("click.rsv").on("click.rsv",function(b){a.stopVideo();b.preventDefault();b.stopPropagation();return!1}),b.append(a._c7),a.isIPAD&&b.addClass("rsIOSVideo"),a._f7(!1),setTimeout(function(){a._c7.addClass("rsVideoActive")},10),a.ev.trigger("rsVideoPlay"),a._b7=!0);return!0}return!1},stopVideo:function(){var a=this;return a._b7?(a.isIPAD&&a.slider.find(".rsCloseVideoBtn").remove(),a._f7(!0),setTimeout(function(){a.ev.trigger("rsOnDestroyVideoElement",
33903[a.videoObj]);var d=a._c7.find("iframe");if(d.length)try{d.attr("src","")}catch(b){}a._c7.remove();a._c7=null},16),a.ev.trigger("rsVideoStop"),a._b7=!1,!0):!1},_f7:function(a,d){var b=[],c=this.st.video;c.autoHideArrows&&(this._c2&&(b.push(this._c2,this._d2),this._e2=!a),this._v5&&b.push(this._v5));c.autoHideControlNav&&this._k5&&b.push(this._k5);c.autoHideBlocks&&this._d7.animBlocks&&b.push(this._d7.animBlocks);c.autoHideCaption&&this.globalCaption&&b.push(this.globalCaption);this.slider[a?"removeClass":
33904"addClass"]("rsVideoPlaying");if(b.length)for(c=0;c<b.length;c++)a?b[c].removeClass("rsHidden"):b[c].addClass("rsHidden")}});f.rsModules.video=f.rsProto._z6})(jQuery);
33905// jquery.rs.visible-nearby v1.0.2
33906(function(d){d.rsProto._g7=function(){var a=this;a.st.visibleNearby&&a.st.visibleNearby.enabled&&(a._h7={enabled:!0,centerArea:0.6,center:!0,breakpoint:0,breakpointCenterArea:0.8,hiddenOverflow:!0,navigateByCenterClick:!1},a.st.visibleNearby=d.extend({},a._h7,a.st.visibleNearby),a.ev.one("rsAfterPropsSetup",function(){a._i7=a._e1.css("overflow","visible").wrap('<div class="rsVisibleNearbyWrap"></div>').parent();a.st.visibleNearby.hiddenOverflow||a._i7.css("overflow","visible");a._o1=a.st.controlsInside?
33907a._i7:a.slider}),a.ev.on("rsAfterSizePropSet",function(){var b,c=a.st.visibleNearby;b=c.breakpoint&&a.width<c.breakpoint?c.breakpointCenterArea:c.centerArea;a._h?(a._b4*=b,a._i7.css({height:a._c4,width:a._b4/b}),a._d=a._b4*(1-b)/2/b):(a._c4*=b,a._i7.css({height:a._c4/b,width:a._b4}),a._d=a._c4*(1-b)/2/b);c.navigateByCenterClick||(a._q=a._h?a._b4:a._c4);c.center&&a._e1.css("margin-"+(a._h?"left":"top"),a._d)}))};d.rsModules.visibleNearby=d.rsProto._g7})(jQuery);
33908
33909/*! ScrollMagic v2.0.5 | (c) 2015 Jan Paepke (@janpaepke) | license & info: http://scrollmagic.io */
33910
33911!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.ScrollMagic=t()}(this,function(){"use strict";var e=function(){};e.version="2.0.5",window.addEventListener("mousewheel",function(){});var t="data-scrollmagic-pin-spacer";e.Controller=function(r){var o,s,a="ScrollMagic.Controller",l="FORWARD",c="REVERSE",u="PAUSED",f=n.defaults,d=this,h=i.extend({},f,r),g=[],p=!1,v=0,m=u,w=!0,y=0,S=!0,b=function(){for(var e in h)f.hasOwnProperty(e)||delete h[e];if(h.container=i.get.elements(h.container)[0],!h.container)throw a+" init failed.";w=h.container===window||h.container===document.body||!document.body.contains(h.container),w&&(h.container=window),y=z(),h.container.addEventListener("resize",T),h.container.addEventListener("scroll",T),h.refreshInterval=parseInt(h.refreshInterval)||f.refreshInterval,E()},E=function(){h.refreshInterval>0&&(s=window.setTimeout(A,h.refreshInterval))},x=function(){return h.vertical?i.get.scrollTop(h.container):i.get.scrollLeft(h.container)},z=function(){return h.vertical?i.get.height(h.container):i.get.width(h.container)},C=this._setScrollPos=function(e){h.vertical?w?window.scrollTo(i.get.scrollLeft(),e):h.container.scrollTop=e:w?window.scrollTo(e,i.get.scrollTop()):h.container.scrollLeft=e},F=function(){if(S&&p){var e=i.type.Array(p)?p:g.slice(0);p=!1;var t=v;v=d.scrollPos();var n=v-t;0!==n&&(m=n>0?l:c),m===c&&e.reverse(),e.forEach(function(e){e.update(!0)})}},L=function(){o=i.rAF(F)},T=function(e){"resize"==e.type&&(y=z(),m=u),p!==!0&&(p=!0,L())},A=function(){if(!w&&y!=z()){var e;try{e=new Event("resize",{bubbles:!1,cancelable:!1})}catch(t){e=document.createEvent("Event"),e.initEvent("resize",!1,!1)}h.container.dispatchEvent(e)}g.forEach(function(e){e.refresh()}),E()};this._options=h;var O=function(e){if(e.length<=1)return e;var t=e.slice(0);return t.sort(function(e,t){return e.scrollOffset()>t.scrollOffset()?1:-1}),t};return this.addScene=function(t){if(i.type.Array(t))t.forEach(function(e){d.addScene(e)});else if(t instanceof e.Scene)if(t.controller()!==d)t.addTo(d);else if(g.indexOf(t)<0){g.push(t),g=O(g),t.on("shift.controller_sort",function(){g=O(g)});for(var n in h.globalSceneOptions)t[n]&&t[n].call(t,h.globalSceneOptions[n])}return d},this.removeScene=function(e){if(i.type.Array(e))e.forEach(function(e){d.removeScene(e)});else{var t=g.indexOf(e);t>-1&&(e.off("shift.controller_sort"),g.splice(t,1),e.remove())}return d},this.updateScene=function(t,n){return i.type.Array(t)?t.forEach(function(e){d.updateScene(e,n)}):n?t.update(!0):p!==!0&&t instanceof e.Scene&&(p=p||[],-1==p.indexOf(t)&&p.push(t),p=O(p),L()),d},this.update=function(e){return T({type:"resize"}),e&&F(),d},this.scrollTo=function(n,r){if(i.type.Number(n))C.call(h.container,n,r);else if(n instanceof e.Scene)n.controller()===d&&d.scrollTo(n.scrollOffset(),r);else if(i.type.Function(n))C=n;else{var o=i.get.elements(n)[0];if(o){for(;o.parentNode.hasAttribute(t);)o=o.parentNode;var s=h.vertical?"top":"left",a=i.get.offset(h.container),l=i.get.offset(o);
33911w||(a[s]-=d.scrollPos()),d.scrollTo(l[s]-a[s],r)}}return d},this.scrollPos=function(e){return arguments.length?(i.type.Function(e)&&(x=e),d):x.call(d)},this.info=function(e){var t={size:y,vertical:h.vertical,scrollPos:v,scrollDirection:m,container:h.container,isDocument:w};return arguments.length?void 0!==t[e]?t[e]:void 0:t},this.loglevel=function(){return d},this.enabled=function(e){return arguments.length?(S!=e&&(S=!!e,d.updateScene(g,!0)),d):S},this.destroy=function(e){window.clearTimeout(s);for(var t=g.length;t--;)g[t].destroy(e);return h.container.removeEventListener("resize",T),h.container.removeEventListener("scroll",T),i.cAF(o),null},b(),d};var n={defaults:{container:window,vertical:!0,globalSceneOptions:{},loglevel:2,refreshInterval:100}};e.Controller.addOption=function(e,t){n.defaults[e]=t},e.Controller.extend=function(t){var n=this;e.Controller=function(){return n.apply(this,arguments),this.$super=i.extend({},this),t.apply(this,arguments)||this},i.extend(e.Controller,n),e.Controller.prototype=n.prototype,e.Controller.prototype.constructor=e.Controller},e.Scene=function(n){var o,s,a="BEFORE",l="DURING",c="AFTER",u=r.defaults,f=this,d=i.extend({},u,n),h=a,g=0,p={start:0,end:0},v=0,m=!0,w=function(){for(var e in d)u.hasOwnProperty(e)||delete d[e];for(var t in u)L(t);C()},y={};this.on=function(e,t){return i.type.Function(t)&&(e=e.trim().split(" "),e.forEach(function(e){var n=e.split("."),r=n[0],i=n[1];"*"!=r&&(y[r]||(y[r]=[]),y[r].push({namespace:i||"",callback:t}))})),f},this.off=function(e,t){return e?(e=e.trim().split(" "),e.forEach(function(e){var n=e.split("."),r=n[0],i=n[1]||"",o="*"===r?Object.keys(y):[r];o.forEach(function(e){for(var n=y[e]||[],r=n.length;r--;){var o=n[r];!o||i!==o.namespace&&"*"!==i||t&&t!=o.callback||n.splice(r,1)}n.length||delete y[e]})}),f):f},this.trigger=function(t,n){if(t){var r=t.trim().split("."),i=r[0],o=r[1],s=y[i];s&&s.forEach(function(t){o&&o!==t.namespace||t.callback.call(f,new e.Event(i,t.namespace,f,n))})}return f},f.on("change.internal",function(e){"loglevel"!==e.what&&"tweenChanges"!==e.what&&("triggerElement"===e.what?E():"reverse"===e.what&&f.update())}).on("shift.internal",function(){S(),f.update()}),this.addTo=function(t){return t instanceof e.Controller&&s!=t&&(s&&s.removeScene(f),s=t,C(),b(!0),E(!0),S(),s.info("container").addEventListener("resize",x),t.addScene(f),f.trigger("add",{controller:s}),f.update()),f},this.enabled=function(e){return arguments.length?(m!=e&&(m=!!e,f.update(!0)),f):m},this.remove=function(){if(s){s.info("container").removeEventListener("resize",x);var e=s;s=void 0,e.removeScene(f),f.trigger("remove")}return f},this.destroy=function(e){return f.trigger("destroy",{reset:e}),f.remove(),f.off("*.*"),null},this.update=function(e){if(s)if(e)if(s.enabled()&&m){var t,n=s.info("scrollPos");t=d.duration>0?(n-p.start)/(p.end-p.start):n>=p.start?1:0,f.trigger("update",{startPos:p.start,endPos:p.end,scrollPos:n}),f.progress(t)}else T&&h===l&&O(!0);else s.updateScene(f,!1);return f},this.refresh=function(){return b(),E(),f},this.progress=function(e){if(arguments.length){var t=!1,n=h,r=s?s.info("scrollDirection"):"PAUSED",i=d.reverse||e>=g;if(0===d.duration?(t=g!=e,g=1>e&&i?0:1,h=0===g?a:l):0>e&&h!==a&&i?(g=0,h=a,t=!0):e>=0&&1>e&&i?(g=e,h=l,t=!0):e>=1&&h!==c?(g=1,h=c,t=!0):h!==l||i||O(),t){var o={progress:g,state:h,scrollDirection:r},u=h!=n,p=function(e){f.trigger(e,o)};u&&n!==l&&(p("enter"),p(n===a?"start":"end")),p("progress"),u&&h!==l&&(p(h===a?"start":"end"),p("leave"))}return f}return g};var S=function(){p={start:v+d.offset},s&&d.triggerElement&&(p.start-=s.info("size")*d.triggerHook),p.end=p.start+d.duration},b=function(e){if(o){var t="duration";F(t,o.call(f))&&!e&&(f.trigger("change",{what:t,newval:d[t]}),f.trigger("shift",{reason:t}))}},E=function(e){var n=0,r=d.triggerElement;if(s&&r){for(var o=s.info(),a=i.get.offset(o.container),l=o.vertical?"top":"left";r.parentNode.hasAttribute(t);)r=r.parentNode;var c=i.get.offset(r);o.isDocument||(a[l]-=s.scrollPos()),n=c[l]-a[l]}var u=n!=v;v=n,u&&!e&&f.trigger("shift",{reason:"triggerElementPosition"})},x=function(){d.triggerHook>0&&f.trigger("shift",{reason:"containerResize"})},z=i.extend(r.validate,{duration:function(e){if(i.type.String(e)&&e.match(/^(\.|\d)*\d+%$/)){var t=parseFloat(e)/100;e=function(){return s?s.info("size")*t:0}}if(i.type.Function(e)){o=e;try{e=parseFloat(o())}catch(t){e=-1}}if(e=parseFloat(e),!i.type.Number(e)||0>e)throw o?(o=void 0,0):0;return e}}),C=function(e){e=arguments.length?[e]:Object.keys(z),e.forEach(function(e){var t;if(z[e])try{t=z[e](d[e])}catch(n){t=u[e]}finally{d[e]=t}})},F=function(e,t){var n=!1,r=d[e];return d[e]!=t&&(d[e]=t,C(e),n=r!=d[e]),n},L=function(e){f[e]||(f[e]=function(t){return arguments.length?("duration"===e&&(o=void 0),F(e,t)&&(f.trigger("change",{what:e,newval:d[e]}),r.shifts.indexOf(e)>-1&&f.trigger("shift",{reason:e})),f):d[e]})};this.controller=function(){return s},this.state=function(){return h},this.scrollOffset=function(){return p.start},this.triggerPosition=function(){var e=d.offset;return s&&(e+=d.triggerElement?v:s.info("size")*f.triggerHook()),e};var T,A;f.on("shift.internal",function(e){var t="duration"===e.reason;(h===c&&t||h===l&&0===d.duration)&&O(),t&&_()}).on("progress.internal",function(){O()}).on("add.internal",function(){_()}).on("destroy.internal",function(e){f.removePin(e.reset)});var O=function(e){if(T&&s){var t=s.info(),n=A.spacer.firstChild;if(e||h!==l){var r={position:A.inFlow?"relative":"absolute",top:0,left:0},o=i.css(n,"position")!=r.position;A.pushFollowers?d.duration>0&&(h===c&&0===parseFloat(i.css(A.spacer,"padding-top"))?o=!0:h===a&&0===parseFloat(i.css(A.spacer,"padding-bottom"))&&(o=!0)):r[t.vertical?"top":"left"]=d.duration*g,i.css(n,r),o&&_()}else{"fixed"!=i.css(n,"position")&&(i.css(n,{position:"fixed"}),_());var u=i.get.offset(A.spacer,!0),f=d.reverse||0===d.duration?t.scrollPos-p.start:Math.round(g*d.duration*10)/10;u[t.vertical?"top":"left"]+=f,i.css(A.spacer.firstChild,{top:u.top,left
33911:u.left})}}},_=function(){if(T&&s&&A.inFlow){var e=h===l,t=s.info("vertical"),n=A.spacer.firstChild,r=i.isMarginCollapseType(i.css(A.spacer,"display")),o={};A.relSize.width||A.relSize.autoFullWidth?e?i.css(T,{width:i.get.width(A.spacer)}):i.css(T,{width:"100%"}):(o["min-width"]=i.get.width(t?T:n,!0,!0),o.width=e?o["min-width"]:"auto"),A.relSize.height?e?i.css(T,{height:i.get.height(A.spacer)-(A.pushFollowers?d.duration:0)}):i.css(T,{height:"100%"}):(o["min-height"]=i.get.height(t?n:T,!0,!r),o.height=e?o["min-height"]:"auto"),A.pushFollowers&&(o["padding"+(t?"Top":"Left")]=d.duration*g,o["padding"+(t?"Bottom":"Right")]=d.duration*(1-g)),i.css(A.spacer,o)}},N=function(){s&&T&&h===l&&!s.info("isDocument")&&O()},P=function(){s&&T&&h===l&&((A.relSize.width||A.relSize.autoFullWidth)&&i.get.width(window)!=i.get.width(A.spacer.parentNode)||A.relSize.height&&i.get.height(window)!=i.get.height(A.spacer.parentNode))&&_()},D=function(e){s&&T&&h===l&&!s.info("isDocument")&&(e.preventDefault(),s._setScrollPos(s.info("scrollPos")-((e.wheelDelta||e[s.info("vertical")?"wheelDeltaY":"wheelDeltaX"])/3||30*-e.detail)))};this.setPin=function(e,n){var r={pushFollowers:!0,spacerClass:"scrollmagic-pin-spacer"};if(n=i.extend({},r,n),e=i.get.elements(e)[0],!e)return f;if("fixed"===i.css(e,"position"))return f;if(T){if(T===e)return f;f.removePin()}T=e;var o=T.parentNode.style.display,s=["top","left","bottom","right","margin","marginLeft","marginRight","marginTop","marginBottom"];T.parentNode.style.display="none";var a="absolute"!=i.css(T,"position"),l=i.css(T,s.concat(["display"])),c=i.css(T,["width","height"]);T.parentNode.style.display=o,!a&&n.pushFollowers&&(n.pushFollowers=!1);var u=T.parentNode.insertBefore(document.createElement("div"),T),d=i.extend(l,{position:a?"relative":"absolute",boxSizing:"content-box",mozBoxSizing:"content-box",webkitBoxSizing:"content-box"});if(a||i.extend(d,i.css(T,["width","height"])),i.css(u,d),u.setAttribute(t,""),i.addClass(u,n.spacerClass),A={spacer:u,relSize:{width:"%"===c.width.slice(-1),height:"%"===c.height.slice(-1),autoFullWidth:"auto"===c.width&&a&&i.isMarginCollapseType(l.display)},pushFollowers:n.pushFollowers,inFlow:a},!T.___origStyle){T.___origStyle={};var h=T.style,g=s.concat(["width","height","position","boxSizing","mozBoxSizing","webkitBoxSizing"]);g.forEach(function(e){T.___origStyle[e]=h[e]||""})}return A.relSize.width&&i.css(u,{width:c.width}),A.relSize.height&&i.css(u,{height:c.height}),u.appendChild(T),i.css(T,{position:a?"relative":"absolute",margin:"auto",top:"auto",left:"auto",bottom:"auto",right:"auto"}),(A.relSize.width||A.relSize.autoFullWidth)&&i.css(T,{boxSizing:"border-box",mozBoxSizing:"border-box",webkitBoxSizing:"border-box"}),window.addEventListener("scroll",N),window.addEventListener("resize",N),window.addEventListener("resize",P),T.addEventListener("mousewheel",D),T.addEventListener("DOMMouseScroll",D),O(),f},this.removePin=function(e){if(T){if(h===l&&O(!0),e||!s){var n=A.spacer.firstChild;if(n.hasAttribute(t)){var r=A.spacer.style,o=["margin","marginLeft","marginRight","marginTop","marginBottom"];margins={},o.forEach(function(e){margins[e]=r[e]||""}),i.css(n,margins)}A.spacer.parentNode.insertBefore(n,A.spacer),A.spacer.parentNode.removeChild(A.spacer),T.parentNode.hasAttribute(t)||(i.css(T,T.___origStyle),delete T.___origStyle)}window.removeEventListener("scroll",N),window.removeEventListener("resize",N),window.removeEventListener("resize",P),T.removeEventListener("mousewheel",D),T.removeEventListener("DOMMouseScroll",D),T=void 0}return f};var R,k=[];return f.on("destroy.internal",function(e){f.removeClassToggle(e.reset)}),this.setClassToggle=function(e,t){var n=i.get.elements(e);return 0!==n.length&&i.type.String(t)?(k.length>0&&f.removeClassToggle(),R=t,k=n,f.on("enter.internal_class leave.internal_class",function(e){var t="enter"===e.type?i.addClass:i.removeClass;k.forEach(function(e){t(e,R)})}),f):f},this.removeClassToggle=function(e){return e&&k.forEach(function(e){i.removeClass(e,R)}),f.off("start.internal_class end.internal_class"),R=void 0,k=[],f},w(),f};var r={defaults:{duration:0,offset:0,triggerElement:void 0,triggerHook:.5,reverse:!0,loglevel:2},validate:{offset:function(e){if(e=parseFloat(e),!i.type.Number(e))throw 0;return e},triggerElement:function(e){if(e=e||void 0){var t=i.get.elements(e)[0];if(!t)throw 0;e=t}return e},triggerHook:function(e){var t={onCenter:.5,onEnter:1,onLeave:0};if(i.type.Number(e))e=Math.max(0,Math.min(parseFloat(e),1));else{if(!(e in t))throw 0;e=t[e]}return e},reverse:function(e){return!!e}},shifts:["duration","offset","triggerHook"]};e.Scene.addOption=function(e,t,n,i){e in r.defaults||(r.defaults[e]=t,r.validate[e]=n,i&&r.shifts.push(e))},e.Scene.extend=function(t){var n=this;e.Scene=function(){return n.apply(this,arguments),this.$super=i.extend({},this),t.apply(this,arguments)||this},i.extend(e.Scene,n),e.Scene.prototype=n.prototype,e.Scene.prototype.constructor=e.Scene},e.Event=function(e,t,n,r){r=r||{};for(var i in r)this[i]=r[i];return this.type=e,this.target=this.currentTarget=n,this.namespace=t||"",this.timeStamp=this.timestamp=Date.now(),this};var i=e._util=function(e){var t,n={},r=function(e){return parseFloat(e)||0},i=function(t){return t.currentStyle?t.currentStyle:e.getComputedStyle(t)}
33911,o=function(t,n,o,s){if(n=n===document?e:n,n===e)s=!1;else if(!f.DomElement(n))return 0;t=t.charAt(0).toUpperCase()+t.substr(1).toLowerCase();var a=(o?n["offset"+t]||n["outer"+t]:n["client"+t]||n["inner"+t])||0;if(o&&s){var l=i(n);a+="Height"===t?r(l.marginTop)+r(l.marginBottom):r(l.marginLeft)+r(l.marginRight)}return a},s=function(e){return e.replace(/^[^a-z]+([a-z])/g,"$1").replace(/-([a-z])/g,function(e){return e[1].toUpperCase()})};n.extend=function(e){for(e=e||{},t=1;t<arguments.length;t++)if(arguments[t])for(var n in arguments[t])arguments[t].hasOwnProperty(n)&&(e[n]=arguments[t][n]);return e},n.isMarginCollapseType=function(e){return["block","flex","list-item","table","-webkit-box"].indexOf(e)>-1};var a=0,l=["ms","moz","webkit","o"],c=e.requestAnimationFrame,u=e.cancelAnimationFrame;for(t=0;!c&&t<l.length;++t)c=e[l[t]+"RequestAnimationFrame"],u=e[l[t]+"CancelAnimationFrame"]||e[l[t]+"CancelRequestAnimationFrame"];c||(c=function(t){var n=(new Date).getTime(),r=Math.max(0,16-(n-a)),i=e.setTimeout(function(){t(n+r)},r);return a=n+r,i}),u||(u=function(t){e.clearTimeout(t)}),n.rAF=c.bind(e),n.cAF=u.bind(e);var f=n.type=function(e){return Object.prototype.toString.call(e).replace(/^\[object (.+)\]$/,"$1").toLowerCase()};f.String=function(e){return"string"===f(e)},f.Function=function(e){return"function"===f(e)},f.Array=function(e){return Array.isArray(e)},f.Number=function(e){return!f.Array(e)&&e-parseFloat(e)+1>=0},f.DomElement=function(e){return"object"==typeof HTMLElement?e instanceof HTMLElement:e&&"object"==typeof e&&null!==e&&1===e.nodeType&&"string"==typeof e.nodeName};var d=n.get={};return d.elements=function(t){var n=[];if(f.String(t))try{t=document.querySelectorAll(t)}catch(e){return n}if("nodelist"===f(t)||f.Array(t))for(var r=0,i=n.length=t.length;i>r;r++){var o=t[r];n[r]=f.DomElement(o)?o:d.elements(o)}else(f.DomElement(t)||t===document||t===e)&&(n=[t]);return n},d.scrollTop=function(t){return t&&"number"==typeof t.scrollTop?t.scrollTop:e.pageYOffset||0},d.scrollLeft=function(t){return t&&"number"==typeof t.scrollLeft?t.scrollLeft:e.pageXOffset||0},d.width=function(e,t,n){return o("width",e,t,n)},d.height=function(e,t,n){return o("height",e,t,n)},d.offset=function(e,t){var n={top:0,left:0};if(e&&e.getBoundingClientRect){var r=e.getBoundingClientRect();n.top=r.top,n.left=r.left,t||(n.top+=d.scrollTop(),n.left+=d.scrollLeft())}return n},n.addClass=function(e,t){t&&(e.classList?e.classList.add(t):e.className+=" "+t)},n.removeClass=function(e,t){t&&(e.classList?e.classList.remove(t):e.className=e.className.replace(RegExp("(^|\\b)"+t.split(" ").join("|")+"(\\b|$)","gi")," "))},n.css=function(e,t){if(f.String(t))return i(e)[s(t)];if(f.Array(t)){var n={},r=i(e);return t.forEach(function(e){n[e]=r[s(e)]}),n}for(var o in t){var a=t[o];a==parseFloat(a)&&(a+="px"),e.style[s(o)]=a}},n}(window||{});return e});
33912
33913(function(){
33914
33915    var videoPlayerOverlay = function () {
33916
33917        //getparameter by name (needed to get the youtube id - non-shared)
33918        function getParameterByName(name, url) {
33919            if (!url) url = window.location.href;
33920            name = name.replace(/[\[\]]/g, "\\$&");
33921            var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)", "i"),
33922                results = regex.exec(url);
33923            if (!results) return null;
33924            if (!results[2]) return '';
33925            return decodeURIComponent(results[2].replace(/\+/g, " "));
33926        }
33927
33928        //Open video overlay.............................................
33929        $(".open-video-overlay, .rte-open-video-overlay a").click(function (event) {
33930            event.preventDefault();
33931
33932            var videoUrl = $(this).attr("href");
33933            var sharedYouTubeLink = "https://youtu.be/";
33934            var vimeoLink = "https://vimeo.com/";
33935            var videoId;
33936            var embedUrl;
33937
33938            if(videoUrl.indexOf(vimeoLink) > -1) {
33939                videoId = videoUrl.replace(vimeoLink, '');
33940                var embedUrl = 'https://player.vimeo.com/video/' + videoId + '?autoplay=1" width="500" height="300" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen';
33941            }
33942            else if(videoUrl.indexOf(sharedYouTubeLink) > -1) {
33943                videoId = videoUrl.replace(sharedYouTubeLink, '');
33944                embedUrl = '//www.youtube.com/embed/' + videoId + '?enablejsapi=1&rel=0&autoplay=1&showinfo=0&wmode=transparent';
33945            } 
33946            else {
33947                videoId = getParameterByName('v', videoUrl); 
33948                embedUrl = '//www.youtube.com/embed/' + videoId + '?enablejsapi=1&rel=0&autoplay=1&showinfo=0&wmode=transparent';
33949            }
33950
33951            //Embed iframe source + open overlay
33952            $("#fullpage-player").attr("src", embedUrl);
33953            $("html").addClass("fullpage-overlay-opened");
33954            $("#top").addClass("top-slim-header");
33955
33956        });
33957
33958        //Close video overlay............................................
33959        $("#close-fullpage-overlay").click(function () {
33960            $("html").removeClass("fullpage-overlay-opened"); 
33961            $("#top").removeClass("top-slim-header");
33962            setTimeout(function(){ 
33963                $("#fullpage-player").attr("src", "about:blank");
33964            }, 1000);
33965        });
33966    }
33967
33968    var videoPlayer = function () {
33969
33970        $(".video-overlay-image").click(function () {
33971
33972        	var parentContainer = $(this).parents(".video-container");
33973            var thisVideo = parentContainer.find(".video-id").html();
33974            var wrapper = $(this).parents(".module-video");
33975
33976            if ( parentContainer.find( ".vimeo-video-container" ).length ) {
33977            	var embedUrl = 'https://player.vimeo.com/video/' + thisVideo + '?autoplay=1" width="500" height="300" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen';
33978
33979            	if($(wrapper).is(".show-in-overlay")) {
33980                    $('#fullpage-player').attr('src', embedUrl);
33981                    $('html').addClass('fullpage-overlay-opened');
33982                    $('body').addClass('top-slim-header');
33983               	}
33984                else {
33985                	parentContainer.find(".video-overlay-image").fadeOut();
33986               	 	parentContainer.find(".video-id").html('<iframe src="' + embedUrl + '"></iframe>');
33987                }	
33988            } 
33989            else {
33990            	var embedUrl = '//www.youtube.com/embed/' + thisVideo + '?enablejsapi=1&rel=0&autoplay=1&showinfo=0&wmode=transparent';
33991
33992            	if($(wrapper).is(".show-in-overlay")) {
33993                    $('#fullpage-player').attr('src', embedUrl);
33994                    $('html').addClass('fullpage-overlay-opened');
33995                    $('body').addClass('top-slim-header');
33996               	}
33997                else {
33998        	        parentContainer.find('.video-overlay-image').fadeOut();
33999        	        parentContainer.find(".video-id").html('<iframe src="' + embedUrl + '"></iframe>');
34000                }
34001            } 
34002                 
34003        });
34004    }
34005
34006    $(document).ready(function() {
34007        videoPlayer();
34008        videoPlayerOverlay();
34009    });
34010
34011})();
34012
34013var app = angular.module('HeydayThemeApp', ['ngAnimate']).constant('BASE_API_URI', '/umbraco/api/');
34014app.controller('DistributorsController', ["$scope", function ($scope) {
34015    var formOpened = false;
34016    $scope.enyDistributor = function () {
34017        if ($scope.country == "default") {
34018            return false;
34019        }
34020        var result = true;
34021        $.each($scope.distributors, function () {
34022            if (this.Country == $scope.country) {
34023                result = false;
34024                return result;
34025            }
34026        });
34027        if (result == true && formOpened == false) {
34028            formOpened = true;
34029            $(".open-contact-form").trigger("click");
34030        }
34031        return result;
34032    };
34033}]);
34034//# sourceMappingURL=app.js.map
34035app.factory('Category', function ($http, BASE_API_URI) {
34036    return {
34037        getProducts: function () {
34038            var params = {
34039                lang: $("#lang").val()
34040            };
34041            return $http.post(BASE_API_URI + "Products/GetProducts", params);
34042        }
34043    };
34044});
34045//# sourceMappingURL=category.js.map
34046app.controller('CategoryController', ["$scope", "Category", "$animate", function ($scope, service, $animate) {
34047    $scope.filter = filter;
34048    $scope.products = null;
34049    service.getProducts().then(function (response) {
34050        $scope.products = response.data;
34051    });
34052    $scope.$watch('filter', function () {
34053    }, true);
34054    function isFilterActive(filter) {
34055        return _.isEmpty(_.filter(filter, _.identity));
34056    }
34057    function inArray(item, array) {
34058        var result = false;
34059        $.each(array, function () {
34060            if (item[this] == true) {
34061                result = true;
34062            }
34063        });
34064        return result;
34065    }
34066    $scope.hasExtraProducts = function () {
34067        var value = false;
34068        if ($scope.products != null) {
34069            $.each($scope.products, function () {
34070                if (this.isExtra && $scope.visible(this)) {
34071                    value = true;
34072                    return;
34073                }
34074            });
34075        }
34076        return value;
34077    };
34078    $scope.enyProducts = function () {
34079        var result = false;
34080        $.each($scope.products, function () {
34081            if ($scope.visible(this)) {
34082                result = true;
34083                return result;
34084            }
34085        });
34086        return result;
34087    };
34088    var isEnyCategorySelected = function (filter) {
34089        var result = false;
34090        _.each(filter, function (item) {
34091            if (item) {
34092                result = true;
34093            }
34094        });
34095        return result;
34096    };
34097    $scope.visible = function (product) {
34098        if (product != undefined) {
34099            var result = true;
34100            $.each($scope.filter, function (index) {
34101                var filter = this;
34102                if (index == "category") {
34103                    if (isFilterActive($scope.filter.category) || $scope.filter.category[product.categoryId]) {
34104                    }
34105                    else {
34106                        result = false;
34107                    }
34108                }
34109                else if ((Object.getOwnPropertyNames(filter).length == 0 || !isEnyCategorySelected(filter)) && result == true || inArray(filter, product.categories) && result == true) {
34110                }
34111                else {
34112                    result = false;
34113                }
34114            });
34115            return result;
34116        }
34117    };
34118}]);
34119//# sourceMappingURL=category.js.map
34120/**
34121 * Owl Carousel v2.2.1
34122 * Copyright 2013-2017 David Deutsch
34123 * Licensed under  ()
34124 */
34125/**
34126 * Owl carousel
34127 * @version 2.1.6
34128 * @author Bartosz Wojciechowski
34129 * @author David Deutsch
34130 * @license The MIT License (MIT)
34131 * @todo Lazy Load Icon
34132 * @todo prevent animationend bubling
34133 * @todo itemsScaleUp
34134 * @todo Test Zepto
34135 * @todo stagePadding calculate wrong active classes
34136 */
34137;(function($, window, document, undefined) {
34138
34139	/**
34140	 * Creates a carousel.
34141	 * @class The Owl Carousel.
34142	 * @public
34143	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
34144	 * @param {Object} [options] - The options
34145	 */
34146	function Owl(element, options) {
34147
34148		/**
34149		 * Current settings for the carousel.
34150		 * @public
34151		 */
34152		this.settings = null;
34153
34154		/**
34155		 * Current options set by the caller including defaults.
34156		 * @public
34157		 */
34158		this.options = $.extend({}, Owl.Defaults, options);
34159
34160		/**
34161		 * Plugin element.
34162		 * @public
34163		 */
34164		this.$element = $(element);
34165
34166		/**
34167		 * Proxied event handlers.
34168		 * @protected
34169		 */
34170		this._handlers = {};
34171
34172		/**
34173		 * References to the running plugins of this carousel.
34174		 * @protected
34175		 */
34176		this._plugins = {};
34177
34178		/**
34179		 * Currently suppressed events to prevent them from beeing retriggered.
34180		 * @protected
34181		 */
34182		this._supress = {};
34183
34184		/**
34185		 * Absolute current position.
34186		 * @protected
34187		 */
34188		this._current = null;
34189
34190		/**
34191		 * Animation speed in milliseconds.
34192		 * @protected
34193		 */
34194		this._speed = null;
34195
34196		/**
34197		 * Coordinates of all items in pixel.
34198		 * @todo The name of this member is missleading.
34199		 * @protected
34200		 */
34201		this._coordinates = [];
34202
34203		/**
34204		 * Current breakpoint.
34205		 * @todo Real media queries would be nice.
34206		 * @protected
34207		 */
34208		this._breakpoint = null;
34209
34210		/**
34211		 * Current width of the plugin element.
34212		 */
34213		this._width = null;
34214
34215		/**
34216		 * All real items.
34217		 * @protected
34218		 */
34219		this._items = [];
34220
34221		/**
34222		 * All cloned items.
34223		 * @protected
34224		 */
34225		this._clones = [];
34226
34227		/**
34228		 * Merge values of all items.
34229		 * @todo Maybe this could be part of a plugin.
34230		 * @protected
34231		 */
34232		this._mergers = [];
34233
34234		/**
34235		 * Widths of all items.
34236		 */
34237		this._widths = [];
34238
34239		/**
34240		 * Invalidated parts within the update process.
34241		 * @protected
34242		 */
34243		this._invalidated = {};
34244
34245		/**
34246		 * Ordered list of workers for the update process.
34247		 * @protected
34248		 */
34249		this._pipe = [];
34250
34251		/**
34252		 * Current state information for the drag operation.
34253		 * @todo #261
34254		 * @protected
34255		 */
34256		this._drag = {
34257			time: null,
34258			target: null,
34259			pointer: null,
34260			stage: {
34261				start: null,
34262				current: null
34263			},
34264			direction: null
34265		};
34266
34267		/**
34268		 * Current state information and their tags.
34269		 * @type {Object}
34270		 * @protected
34271		 */
34272		this._states = {
34273			current: {},
34274			tags: {
34275				'initializing': [ 'busy' ],
34276				'animating': [ 'busy' ],
34277				'dragging': [ 'interacting' ]
34278			}
34279		};
34280
34281		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
34282			this._handlers[handler] = $.proxy(this[handler], this);
34283		}, this));
34284
34285		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
34286			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
34287				= new plugin(this);
34288		}, this));
34289
34290		$.each(Owl.Workers, $.proxy(function(priority, worker) {
34291			this._pipe.push({
34292				'filter': worker.filter,
34293				'run': $.proxy(worker.run, this)
34294			});
34295		}, this));
34296
34297		this.setup();
34298		this.initialize();
34299	}
34300
34301	/**
34302	 * Default options for the carousel.
34303	 * @public
34304	 */
34305	Owl.Defaults = {
34306		items: 3,
34307		loop: false,
34308		center: false,
34309		rewind: false,
34310
vendor: 4,168 bytes, lines 34311-34485
34311		mouseDrag: true,
34312		touchDrag: true,
34313		pullDrag: true,
34314		freeDrag: false,
34315
34316		margin: 0,
34317		stagePadding: 0,
34318
34319		merge: false,
34320		mergeFit: true,
34321		autoWidth: false,
34322
34323		startPosition: 0,
34324		rtl: false,
34325
34326		smartSpeed: 250,
34327		fluidSpeed: false,
34328		dragEndSpeed: false,
34329
34330		responsive: {},
34331		responsiveRefreshRate: 200,
34332		responsiveBaseElement: window,
34333
34334		fallbackEasing: 'swing',
34335
34336		info: false,
34337
34338		nestedItemSelector: false,
34339		itemElement: 'div',
34340		stageElement: 'div',
34341
34342		refreshClass: 'owl-refresh',
34343		loadedClass: 'owl-loaded',
34344		loadingClass: 'owl-loading',
34345		rtlClass: 'owl-rtl',
34346		responsiveClass: 'owl-responsive',
34347		dragClass: 'owl-drag',
34348		itemClass: 'owl-item',
34349		stageClass: 'owl-stage',
34350		stageOuterClass: 'owl-stage-outer',
34351		grabClass: 'owl-grab'
34352	};
34353
34354	/**
34355	 * Enumeration for width.
34356	 * @public
34357	 * @readonly
34358	 * @enum {String}
34359	 */
34360	Owl.Width = {
34361		Default: 'default',
34362		Inner: 'inner',
34363		Outer: 'outer'
34364	};
34365
34366	/**
34367	 * Enumeration for types.
34368	 * @public
34369	 * @readonly
34370	 * @enum {String}
34371	 */
34372	Owl.Type = {
34373		Event: 'event',
34374		State: 'state'
34375	};
34376
34377	/**
34378	 * Contains all registered plugins.
34379	 * @public
34380	 */
34381	Owl.Plugins = {};
34382
34383	/**
34384	 * List of workers involved in the update process.
34385	 */
34386	Owl.Workers = [ {
34387		filter: [ 'width', 'settings' ],
34388		run: function() {
34389			this._width = this.$element.width();
34390		}
34391	}, {
34392		filter: [ 'width', 'items', 'settings' ],
34393		run: function(cache) {
34394			cache.current = this._items && this._items[this.relative(this._current)];
34395		}
34396	}, {
34397		filter: [ 'items', 'settings' ],
34398		run: function() {
34399			this.$stage.children('.cloned').remove();
34400		}
34401	}, {
34402		filter: [ 'width', 'items', 'settings' ],
34403		run: function(cache) {
34404			var margin = this.settings.margin || '',
34405				grid = !this.settings.autoWidth,
34406				rtl = this.settings.rtl,
34407				css = {
34408					'width': 'auto',
34409					'margin-left': rtl ? margin : '',
34410					'margin-right': rtl ? '' : margin
34411				};
34412
34413			!grid && this.$stage.children().css(css);
34414
34415			cache.css = css;
34416		}
34417	}, {
34418		filter: [ 'width', 'items', 'settings' ],
34419		run: function(cache) {
34420			var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
34421				merge = null,
34422				iterator = this._items.length,
34423				grid = !this.settings.autoWidth,
34424				widths = [];
34425
34426			cache.items = {
34427				merge: false,
34428				width: width
34429			};
34430
34431			while (iterator--) {
34432				merge = this._mergers[iterator];
34433				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
34434
34435				cache.items.merge = merge > 1 || cache.items.merge;
34436
34437				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
34438			}
34439
34440			this._widths = widths;
34441		}
34442	}, {
34443		filter: [ 'items', 'settings' ],
34444		run: function() {
34445			var clones = [],
34446				items = this._items,
34447				settings = this.settings,
34448				// TODO: Should be computed from number of min width items in stage
34449				view = Math.max(settings.items * 2, 4),
34450				size = Math.ceil(items.length / 2) * 2,
34451				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
34452				append = '',
34453				prepend = '';
34454
34455			repeat /= 2;
34456
34457			while (repeat--) {
34458				// Switch to only using appended clones
34459				clones.push(this.normalize(clones.length / 2, true));
34460				append = append + items[clones[clones.length - 1]][0].outerHTML;
34461				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
34462				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
34463			}
34464
34465			this._clones = clones;
34466
34467			$(append).addClass('cloned').appendTo(this.$stage);
34468			$(prepend).addClass('cloned').prependTo(this.$stage);
34469		}
34470	}, {
34471		filter: [ 'width', 'items', 'settings' ],
34472		run: function() {
34473			var rtl = this.settings.rtl ? 1 : -1,
34474				size = this._clones.length + this._items.length,
34475				iterator = -1,
34476				previous = 0,
34477				current = 0,
34478				coordinates = [];
34479
34480			while (++iterator < size) {
34481				previous = coordinates[iterator - 1] || 0;
34482				current = this._widths[this.relative(iterator)] + this.settings.margin;
34483				coordinates.push(previous + current * rtl);
34484			}
34485
vendor: 8,251 bytes, lines 34486-34797
34486			this._coordinates = coordinates;
34487		}
34488	}, {
34489		filter: [ 'width', 'items', 'settings' ],
34490		run: function() {
34491			var padding = this.settings.stagePadding,
34492				coordinates = this._coordinates,
34493				css = {
34494					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
34495					'padding-left': padding || '',
34496					'padding-right': padding || ''
34497				};
34498
34499			this.$stage.css(css);
34500		}
34501	}, {
34502		filter: [ 'width', 'items', 'settings' ],
34503		run: function(cache) {
34504			var iterator = this._coordinates.length,
34505				grid = !this.settings.autoWidth,
34506				items = this.$stage.children();
34507
34508			if (grid && cache.items.merge) {
34509				while (iterator--) {
34510					cache.css.width = this._widths[this.relative(iterator)];
34511					items.eq(iterator).css(cache.css);
34512				}
34513			} else if (grid) {
34514				cache.css.width = cache.items.width;
34515				items.css(cache.css);
34516			}
34517		}
34518	}, {
34519		filter: [ 'items' ],
34520		run: function() {
34521			this._coordinates.length < 1 && this.$stage.removeAttr('style');
34522		}
34523	}, {
34524		filter: [ 'width', 'items', 'settings' ],
34525		run: function(cache) {
34526			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
34527			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
34528			this.reset(cache.current);
34529		}
34530	}, {
34531		filter: [ 'position' ],
34532		run: function() {
34533			this.animate(this.coordinates(this._current));
34534		}
34535	}, {
34536		filter: [ 'width', 'position', 'items', 'settings' ],
34537		run: function() {
34538			var rtl = this.settings.rtl ? 1 : -1,
34539				padding = this.settings.stagePadding * 2,
34540				begin = this.coordinates(this.current()) + padding,
34541				end = begin + this.width() * rtl,
34542				inner, outer, matches = [], i, n;
34543
34544			for (i = 0, n = this._coordinates.length; i < n; i++) {
34545				inner = this._coordinates[i - 1] || 0;
34546				outer = Math.abs(this._coordinates[i]) + padding * rtl;
34547
34548				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
34549					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
34550					matches.push(i);
34551				}
34552			}
34553
34554			this.$stage.children('.active').removeClass('active');
34555			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
34556
34557			if (this.settings.center) {
34558				this.$stage.children('.center').removeClass('center');
34559				this.$stage.children().eq(this.current()).addClass('center');
34560			}
34561		}
34562	} ];
34563
34564	/**
34565	 * Initializes the carousel.
34566	 * @protected
34567	 */
34568	Owl.prototype.initialize = function() {
34569		this.enter('initializing');
34570		this.trigger('initialize');
34571
34572		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
34573
34574		if (this.settings.autoWidth && !this.is('pre-loading')) {
34575			var imgs, nestedSelector, width;
34576			imgs = this.$element.find('img');
34577			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
34578			width = this.$element.children(nestedSelector).width();
34579
34580			if (imgs.length && width <= 0) {
34581				this.preloadAutoWidthImages(imgs);
34582			}
34583		}
34584
34585		this.$element.addClass(this.options.loadingClass);
34586
34587		// create stage
34588		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
34589			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
34590
34591		// append stage
34592		this.$element.append(this.$stage.parent());
34593
34594		// append content
34595		this.replace(this.$element.children().not(this.$stage.parent()));
34596
34597		// check visibility
34598		if (this.$element.is(':visible')) {
34599			// update view
34600			this.refresh();
34601		} else {
34602			// invalidate width
34603			this.invalidate('width');
34604		}
34605
34606		this.$element
34607			.removeClass(this.options.loadingClass)
34608			.addClass(this.options.loadedClass);
34609
34610		// register event handlers
34611		this.registerEventHandlers();
34612
34613		this.leave('initializing');
34614		this.trigger('initialized');
34615	};
34616
34617	/**
34618	 * Setups the current settings.
34619	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
34620	 * @todo Support for media queries by using `matchMedia` would be nice.
34621	 * @public
34622	 */
34623	Owl.prototype.setup = function() {
34624		var viewport = this.viewport(),
34625			overwrites = this.options.responsive,
34626			match = -1,
34627			settings = null;
34628
34629		if (!overwrites) {
34630			settings = $.extend({}, this.options);
34631		} else {
34632			$.each(overwrites, function(breakpoint) {
34633				if (breakpoint <= viewport && breakpoint > match) {
34634					match = Number(breakpoint);
34635				}
34636			});
34637
34638			settings = $.extend({}, this.options, overwrites[match]);
34639			if (typeof settings.stagePadding === 'function') {
34640				settings.stagePadding = settings.stagePadding();
34641			}
34642			delete settings.responsive;
34643
34644			// responsive class
34645			if (settings.responsiveClass) {
34646				this.$element.attr('class',
34647					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
34648				);
34649			}
34650		}
34651
34652		this.trigger('change', { property: { name: 'settings', value: settings } });
34653		this._breakpoint = match;
34654		this.settings = settings;
34655		this.invalidate('settings');
34656		this.trigger('changed', { property: { name: 'settings', value: this.settings } });
34657	};
34658
34659	/**
34660	 * Updates option logic if necessery.
34661	 * @protected
34662	 */
34663	Owl.prototype.optionsLogic = function() {
34664		if (this.settings.autoWidth) {
34665			this.settings.stagePadding = false;
34666			this.settings.merge = false;
34667		}
34668	};
34669
34670	/**
34671	 * Prepares an item before add.
34672	 * @todo Rename event parameter `content` to `item`.
34673	 * @protected
34674	 * @returns {jQuery|HTMLElement} - The item container.
34675	 */
34676	Owl.prototype.prepare = function(item) {
34677		var event = this.trigger('prepare', { content: item });
34678
34679		if (!event.data) {
34680			event.data = $('<' + this.settings.itemElement + '/>')
34681				.addClass(this.options.itemClass).append(item)
34682		}
34683
34684		this.trigger('prepared', { content: event.data });
34685
34686		return event.data;
34687	};
34688
34689	/**
34690	 * Updates the view.
34691	 * @public
34692	 */
34693	Owl.prototype.update = function() {
34694		var i = 0,
34695			n = this._pipe.length,
34696			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
34697			cache = {};
34698
34699		while (i < n) {
34700			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
34701				this._pipe[i].run(cache);
34702			}
34703			i++;
34704		}
34705
34706		this._invalidated = {};
34707
34708		!this.is('valid') && this.enter('valid');
34709	};
34710
34711	/**
34712	 * Gets the width of the view.
34713	 * @public
34714	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
34715	 * @returns {Number} - The width of the view in pixel.
34716	 */
34717	Owl.prototype.width = function(dimension) {
34718		dimension = dimension || Owl.Width.Default;
34719		switch (dimension) {
34720			case Owl.Width.Inner:
34721			case Owl.Width.Outer:
34722				return this._width;
34723			default:
34724				return this._width - this.settings.stagePadding * 2 + this.settings.margin;
34725		}
34726	};
34727
34728	/**
34729	 * Refreshes the carousel primarily for adaptive purposes.
34730	 * @public
34731	 */
34732	Owl.prototype.refresh = function() {
34733		this.enter('refreshing');
34734		this.trigger('refresh');
34735
34736		this.setup();
34737
34738		this.optionsLogic();
34739
34740		this.$element.addClass(this.options.refreshClass);
34741
34742		this.update();
34743
34744		this.$element.removeClass(this.options.refreshClass);
34745
34746		this.leave('refreshing');
34747		this.trigger('refreshed');
34748	};
34749
34750	/**
34751	 * Checks window `resize` event.
34752	 * @protected
34753	 */
34754	Owl.prototype.onThrottledResize = function() {
34755		window.clearTimeout(this.resizeTimer);
34756		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
34757	};
34758
34759	/**
34760	 * Checks window `resize` event.
34761	 * @protected
34762	 */
34763	Owl.prototype.onResize = function() {
34764		if (!this._items.length) {
34765			return false;
34766		}
34767
34768		if (this._width === this.$element.width()) {
34769			return false;
34770		}
34771
34772		if (!this.$element.is(':visible')) {
34773			return false;
34774		}
34775
34776		this.enter('resizing');
34777
34778		if (this.trigger('resize').isDefaultPrevented()) {
34779			this.leave('resizing');
34780			return false;
34781		}
34782
34783		this.invalidate('width');
34784
34785		this.refresh();
34786
34787		this.leave('resizing');
34788		this.trigger('resized');
34789	};
34790
34791	/**
34792	 * Registers event handlers.
34793	 * @todo Check `msPointerEnabled`
34794	 * @todo #261
34795	 * @protected
34796	 */
34797	Owl.prototype.registerEventHandlers = function() {
vendor: 5,214 bytes, lines 34798-34965
34798		if ($.support.transition) {
34799			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
34800		}
34801
34802		if (this.settings.responsive !== false) {
34803			this.on(window, 'resize', this._handlers.onThrottledResize);
34804		}
34805
34806		if (this.settings.mouseDrag) {
34807			this.$element.addClass(this.options.dragClass);
34808			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
34809			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
34810		}
34811
34812		if (this.settings.touchDrag){
34813			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
34814			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
34815		}
34816	};
34817
34818	/**
34819	 * Handles `touchstart` and `mousedown` events.
34820	 * @todo Horizontal swipe threshold as option
34821	 * @todo #261
34822	 * @protected
34823	 * @param {Event} event - The event arguments.
34824	 */
34825	Owl.prototype.onDragStart = function(event) {
34826		var stage = null;
34827
34828		if (event.which === 3) {
34829			return;
34830		}
34831
34832		if ($.support.transform) {
34833			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
34834			stage = {
34835				x: stage[stage.length === 16 ? 12 : 4],
34836				y: stage[stage.length === 16 ? 13 : 5]
34837			};
34838		} else {
34839			stage = this.$stage.position();
34840			stage = {
34841				x: this.settings.rtl ?
34842					stage.left + this.$stage.width() - this.width() + this.settings.margin :
34843					stage.left,
34844				y: stage.top
34845			};
34846		}
34847
34848		if (this.is('animating')) {
34849			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
34850			this.invalidate('position');
34851		}
34852
34853		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
34854
34855		this.speed(0);
34856
34857		this._drag.time = new Date().getTime();
34858		this._drag.target = $(event.target);
34859		this._drag.stage.start = stage;
34860		this._drag.stage.current = stage;
34861		this._drag.pointer = this.pointer(event);
34862
34863		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
34864
34865		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
34866			var delta = this.difference(this._drag.pointer, this.pointer(event));
34867
34868			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
34869
34870			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
34871				return;
34872			}
34873
34874			event.preventDefault();
34875
34876			this.enter('dragging');
34877			this.trigger('drag');
34878		}, this));
34879	};
34880
34881	/**
34882	 * Handles the `touchmove` and `mousemove` events.
34883	 * @todo #261
34884	 * @protected
34885	 * @param {Event} event - The event arguments.
34886	 */
34887	Owl.prototype.onDragMove = function(event) {
34888		var minimum = null,
34889			maximum = null,
34890			pull = null,
34891			delta = this.difference(this._drag.pointer, this.pointer(event)),
34892			stage = this.difference(this._drag.stage.start, delta);
34893
34894		if (!this.is('dragging')) {
34895			return;
34896		}
34897
34898		event.preventDefault();
34899
34900		if (this.settings.loop) {
34901			minimum = this.coordinates(this.minimum());
34902			maximum = this.coordinates(this.maximum() + 1) - minimum;
34903			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
34904		} else {
34905			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
34906			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
34907			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
34908			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
34909		}
34910
34911		this._drag.stage.current = stage;
34912
34913		this.animate(stage.x);
34914	};
34915
34916	/**
34917	 * Handles the `touchend` and `mouseup` events.
34918	 * @todo #261
34919	 * @todo Threshold for click event
34920	 * @protected
34921	 * @param {Event} event - The event arguments.
34922	 */
34923	Owl.prototype.onDragEnd = function(event) {
34924		var delta = this.difference(this._drag.pointer, this.pointer(event)),
34925			stage = this._drag.stage.current,
34926			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
34927
34928		$(document).off('.owl.core');
34929
34930		this.$element.removeClass(this.options.grabClass);
34931
34932		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
34933			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
34934			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
34935			this.invalidate('position');
34936			this.update();
34937
34938			this._drag.direction = direction;
34939
34940			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
34941				this._drag.target.one('click.owl.core', function() { return false; });
34942			}
34943		}
34944
34945		if (!this.is('dragging')) {
34946			return;
34947		}
34948
34949		this.leave('dragging');
34950		this.trigger('dragged');
34951	};
34952
34953	/**
34954	 * Gets absolute position of the closest item for a coordinate.
34955	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
34956	 * @protected
34957	 * @param {Number} coordinate - The coordinate in pixel.
34958	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
34959	 * @return {Number} - The absolute position of the closest item.
34960	 */
34961	Owl.prototype.closest = function(coordinate, direction) {
34962		var position = -1,
34963			pull = 30,
34964			width = this.width(),
34965			coordinates = this.coordinates();
vendor: 59,760 bytes, lines 34966-37108
34966
34967		if (!this.settings.freeDrag) {
34968			// check closest item
34969			$.each(coordinates, $.proxy(function(index, value) {
34970				// on a left pull, check on current index
34971				if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
34972					position = index;
34973				// on a right pull, check on previous index
34974				// to do so, subtract width from value and set position = index + 1
34975				} else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
34976					position = index + 1;
34977				} else if (this.op(coordinate, '<', value)
34978					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
34979					position = direction === 'left' ? index + 1 : index;
34980				}
34981				return position === -1;
34982			}, this));
34983		}
34984
34985		if (!this.settings.loop) {
34986			// non loop boundries
34987			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
34988				position = coordinate = this.minimum();
34989			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
34990				position = coordinate = this.maximum();
34991			}
34992		}
34993
34994		return position;
34995	};
34996
34997	/**
34998	 * Animates the stage.
34999	 * @todo #270
35000	 * @public
35001	 * @param {Number} coordinate - The coordinate in pixels.
35002	 */
35003	Owl.prototype.animate = function(coordinate) {
35004		var animate = this.speed() > 0;
35005
35006		this.is('animating') && this.onTransitionEnd();
35007
35008		if (animate) {
35009			this.enter('animating');
35010			this.trigger('translate');
35011		}
35012
35013		if ($.support.transform3d && $.support.transition) {
35014			this.$stage.css({
35015				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
35016				transition: (this.speed() / 1000) + 's'
35017			});
35018		} else if (animate) {
35019			this.$stage.animate({
35020				left: coordinate + 'px'
35021			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
35022		} else {
35023			this.$stage.css({
35024				left: coordinate + 'px'
35025			});
35026		}
35027	};
35028
35029	/**
35030	 * Checks whether the carousel is in a specific state or not.
35031	 * @param {String} state - The state to check.
35032	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
35033	 */
35034	Owl.prototype.is = function(state) {
35035		return this._states.current[state] && this._states.current[state] > 0;
35036	};
35037
35038	/**
35039	 * Sets the absolute position of the current item.
35040	 * @public
35041	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
35042	 * @returns {Number} - The absolute position of the current item.
35043	 */
35044	Owl.prototype.current = function(position) {
35045		if (position === undefined) {
35046			return this._current;
35047		}
35048
35049		if (this._items.length === 0) {
35050			return undefined;
35051		}
35052
35053		position = this.normalize(position);
35054
35055		if (this._current !== position) {
35056			var event = this.trigger('change', { property: { name: 'position', value: position } });
35057
35058			if (event.data !== undefined) {
35059				position = this.normalize(event.data);
35060			}
35061
35062			this._current = position;
35063
35064			this.invalidate('position');
35065
35066			this.trigger('changed', { property: { name: 'position', value: this._current } });
35067		}
35068
35069		return this._current;
35070	};
35071
35072	/**
35073	 * Invalidates the given part of the update routine.
35074	 * @param {String} [part] - The part to invalidate.
35075	 * @returns {Array.<String>} - The invalidated parts.
35076	 */
35077	Owl.prototype.invalidate = function(part) {
35078		if ($.type(part) === 'string') {
35079			this._invalidated[part] = true;
35080			this.is('valid') && this.leave('valid');
35081		}
35082		return $.map(this._invalidated, function(v, i) { return i });
35083	};
35084
35085	/**
35086	 * Resets the absolute position of the current item.
35087	 * @public
35088	 * @param {Number} position - The absolute position of the new item.
35089	 */
35090	Owl.prototype.reset = function(position) {
35091		position = this.normalize(position);
35092
35093		if (position === undefined) {
35094			return;
35095		}
35096
35097		this._speed = 0;
35098		this._current = position;
35099
35100		this.suppress([ 'translate', 'translated' ]);
35101
35102		this.animate(this.coordinates(position));
35103
35104		this.release([ 'translate', 'translated' ]);
35105	};
35106
35107	/**
35108	 * Normalizes an absolute or a relative position of an item.
35109	 * @public
35110	 * @param {Number} position - The absolute or relative position to normalize.
35111	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
35112	 * @returns {Number} - The normalized position.
35113	 */
35114	Owl.prototype.normalize = function(position, relative) {
35115		var n = this._items.length,
35116			m = relative ? 0 : this._clones.length;
35117
35118		if (!this.isNumeric(position) || n < 1) {
35119			position = undefined;
35120		} else if (position < 0 || position >= n + m) {
35121			position = ((position - m / 2) % n + n) % n + m / 2;
35122		}
35123
35124		return position;
35125	};
35126
35127	/**
35128	 * Converts an absolute position of an item into a relative one.
35129	 * @public
35130	 * @param {Number} position - The absolute position to convert.
35131	 * @returns {Number} - The converted position.
35132	 */
35133	Owl.prototype.relative = function(position) {
35134		position -= this._clones.length / 2;
35135		return this.normalize(position, true);
35136	};
35137
35138	/**
35139	 * Gets the maximum position for the current item.
35140	 * @public
35141	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
35142	 * @returns {Number}
35143	 */
35144	Owl.prototype.maximum = function(relative) {
35145		var settings = this.settings,
35146			maximum = this._coordinates.length,
35147			iterator,
35148			reciprocalItemsWidth,
35149			elementWidth;
35150
35151		if (settings.loop) {
35152			maximum = this._clones.length / 2 + this._items.length - 1;
35153		} else if (settings.autoWidth || settings.merge) {
35154			iterator = this._items.length;
35155			reciprocalItemsWidth = this._items[--iterator].width();
35156			elementWidth = this.$element.width();
35157			while (iterator--) {
35158				reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
35159				if (reciprocalItemsWidth > elementWidth) {
35160					break;
35161				}
35162			}
35163			maximum = iterator + 1;
35164		} else if (settings.center) {
35165			maximum = this._items.length - 1;
35166		} else {
35167			maximum = this._items.length - settings.items;
35168		}
35169
35170		if (relative) {
35171			maximum -= this._clones.length / 2;
35172		}
35173
35174		return Math.max(maximum, 0);
35175	};
35176
35177	/**
35178	 * Gets the minimum position for the current item.
35179	 * @public
35180	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
35181	 * @returns {Number}
35182	 */
35183	Owl.prototype.minimum = function(relative) {
35184		return relative ? 0 : this._clones.length / 2;
35185	};
35186
35187	/**
35188	 * Gets an item at the specified relative position.
35189	 * @public
35190	 * @param {Number} [position] - The relative position of the item.
35191	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
35192	 */
35193	Owl.prototype.items = function(position) {
35194		if (position === undefined) {
35195			return this._items.slice();
35196		}
35197
35198		position = this.normalize(position, true);
35199		return this._items[position];
35200	};
35201
35202	/**
35203	 * Gets an item at the specified relative position.
35204	 * @public
35205	 * @param {Number} [position] - The relative position of the item.
35206	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
35207	 */
35208	Owl.prototype.mergers = function(position) {
35209		if (position === undefined) {
35210			return this._mergers.slice();
35211		}
35212
35213		position = this.normalize(position, true);
35214		return this._mergers[position];
35215	};
35216
35217	/**
35218	 * Gets the absolute positions of clones for an item.
35219	 * @public
35220	 * @param {Number} [position] - The relative position of the item.
35221	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
35222	 */
35223	Owl.prototype.clones = function(position) {
35224		var odd = this._clones.length / 2,
35225			even = odd + this._items.length,
35226			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
35227
35228		if (position === undefined) {
35229			return $.map(this._clones, function(v, i) { return map(i) });
35230		}
35231
35232		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
35233	};
35234
35235	/**
35236	 * Sets the current animation speed.
35237	 * @public
35238	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
35239	 * @returns {Number} - The current animation speed in milliseconds.
35240	 */
35241	Owl.prototype.speed = function(speed) {
35242		if (speed !== undefined) {
35243			this._speed = speed;
35244		}
35245
35246		return this._speed;
35247	};
35248
35249	/**
35250	 * Gets the coordinate of an item.
35251	 * @todo The name of this method is missleanding.
35252	 * @public
35253	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
35254	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
35255	 */
35256	Owl.prototype.coordinates = function(position) {
35257		var multiplier = 1,
35258			newPosition = position - 1,
35259			coordinate;
35260
35261		if (position === undefined) {
35262			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
35263				return this.coordinates(index);
35264			}, this));
35265		}
35266
35267		if (this.settings.center) {
35268			if (this.settings.rtl) {
35269				multiplier = -1;
35270				newPosition = position + 1;
35271			}
35272
35273			coordinate = this._coordinates[position];
35274			coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
35275		} else {
35276			coordinate = this._coordinates[newPosition] || 0;
35277		}
35278
35279		coordinate = Math.ceil(coordinate);
35280
35281		return coordinate;
35282	};
35283
35284	/**
35285	 * Calculates the speed for a translation.
35286	 * @protected
35287	 * @param {Number} from - The absolute position of the start item.
35288	 * @param {Number} to - The absolute position of the target item.
35289	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
35290	 * @returns {Number} - The time in milliseconds for the translation.
35291	 */
35292	Owl.prototype.duration = function(from, to, factor) {
35293		if (factor === 0) {
35294			return 0;
35295		}
35296
35297		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
35298	};
35299
35300	/**
35301	 * Slides to the specified item.
35302	 * @public
35303	 * @param {Number} position - The position of the item.
35304	 * @param {Number} [speed] - The time in milliseconds for the transition.
35305	 */
35306	Owl.prototype.to = function(position, speed) {
35307		var current = this.current(),
35308			revert = null,
35309			distance = position - this.relative(current),
35310			direction = (distance > 0) - (distance < 0),
35311			items = this._items.length,
35312			minimum = this.minimum(),
35313			maximum = this.maximum();
35314
35315		if (this.settings.loop) {
35316			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
35317				distance += direction * -1 * items;
35318			}
35319
35320			position = current + distance;
35321			revert = ((position - minimum) % items + items) % items + minimum;
35322
35323			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
35324				current = revert - distance;
35325				position = revert;
35326				this.reset(current);
35327			}
35328		} else if (this.settings.rewind) {
35329			maximum += 1;
35330			position = (position % maximum + maximum) % maximum;
35331		} else {
35332			position = Math.max(minimum, Math.min(maximum, position));
35333		}
35334
35335		this.speed(this.duration(current, position, speed));
35336		this.current(position);
35337
35338		if (this.$element.is(':visible')) {
35339			this.update();
35340		}
35341	};
35342
35343	/**
35344	 * Slides to the next item.
35345	 * @public
35346	 * @param {Number} [speed] - The time in milliseconds for the transition.
35347	 */
35348	Owl.prototype.next = function(speed) {
35349		speed = speed || false;
35350		this.to(this.relative(this.current()) + 1, speed);
35351	};
35352
35353	/**
35354	 * Slides to the previous item.
35355	 * @public
35356	 * @param {Number} [speed] - The time in milliseconds for the transition.
35357	 */
35358	Owl.prototype.prev = function(speed) {
35359		speed = speed || false;
35360		this.to(this.relative(this.current()) - 1, speed);
35361	};
35362
35363	/**
35364	 * Handles the end of an animation.
35365	 * @protected
35366	 * @param {Event} event - The event arguments.
35367	 */
35368	Owl.prototype.onTransitionEnd = function(event) {
35369
35370		// if css2 animation then event object is undefined
35371		if (event !== undefined) {
35372			event.stopPropagation();
35373
35374			// Catch only owl-stage transitionEnd event
35375			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
35376				return false;
35377			}
35378		}
35379
35380		this.leave('animating');
35381		this.trigger('translated');
35382	};
35383
35384	/**
35385	 * Gets viewport width.
35386	 * @protected
35387	 * @return {Number} - The width in pixel.
35388	 */
35389	Owl.prototype.viewport = function() {
35390		var width;
35391		if (this.options.responsiveBaseElement !== window) {
35392			width = $(this.options.responsiveBaseElement).width();
35393		} else if (window.innerWidth) {
35394			width = window.innerWidth;
35395		} else if (document.documentElement && document.documentElement.clientWidth) {
35396			width = document.documentElement.clientWidth;
35397		} else {
35398			console.warn('Can not detect viewport width.');
35399		}
35400		return width;
35401	};
35402
35403	/**
35404	 * Replaces the current content.
35405	 * @public
35406	 * @param {HTMLElement|jQuery|String} content - The new content.
35407	 */
35408	Owl.prototype.replace = function(content) {
35409		this.$stage.empty();
35410		this._items = [];
35411
35412		if (content) {
35413			content = (content instanceof jQuery) ? content : $(content);
35414		}
35415
35416		if (this.settings.nestedItemSelector) {
35417			content = content.find('.' + this.settings.nestedItemSelector);
35418		}
35419
35420		content.filter(function() {
35421			return this.nodeType === 1;
35422		}).each($.proxy(function(index, item) {
35423			item = this.prepare(item);
35424			this.$stage.append(item);
35425			this._items.push(item);
35426			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
35427		}, this));
35428
35429		this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
35430
35431		this.invalidate('items');
35432	};
35433
35434	/**
35435	 * Adds an item.
35436	 * @todo Use `item` instead of `content` for the event arguments.
35437	 * @public
35438	 * @param {HTMLElement|jQuery|String} content - The item content to add.
35439	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
35440	 */
35441	Owl.prototype.add = function(content, position) {
35442		var current = this.relative(this._current);
35443
35444		position = position === undefined ? this._items.length : this.normalize(position, true);
35445		content = content instanceof jQuery ? content : $(content);
35446
35447		this.trigger('add', { content: content, position: position });
35448
35449		content = this.prepare(content);
35450
35451		if (this._items.length === 0 || position === this._items.length) {
35452			this._items.length === 0 && this.$stage.append(content);
35453			this._items.length !== 0 && this._items[position - 1].after(content);
35454			this._items.push(content);
35455			this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
35456		} else {
35457			this._items[position].before(content);
35458			this._items.splice(position, 0, content);
35459			this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
35460		}
35461
35462		this._items[current] && this.reset(this._items[current].index());
35463
35464		this.invalidate('items');
35465
35466		this.trigger('added', { content: content, position: position });
35467	};
35468
35469	/**
35470	 * Removes an item by its position.
35471	 * @todo Use `item` instead of `content` for the event arguments.
35472	 * @public
35473	 * @param {Number} position - The relative position of the item to remove.
35474	 */
35475	Owl.prototype.remove = function(position) {
35476		position = this.normalize(position, true);
35477
35478		if (position === undefined) {
35479			return;
35480		}
35481
35482		this.trigger('remove', { content: this._items[position], position: position });
35483
35484		this._items[position].remove();
35485		this._items.splice(position, 1);
35486		this._mergers.splice(position, 1);
35487
35488		this.invalidate('items');
35489
35490		this.trigger('removed', { content: null, position: position });
35491	};
35492
35493	/**
35494	 * Preloads images with auto width.
35495	 * @todo Replace by a more generic approach
35496	 * @protected
35497	 */
35498	Owl.prototype.preloadAutoWidthImages = function(images) {
35499		images.each($.proxy(function(i, element) {
35500			this.enter('pre-loading');
35501			element = $(element);
35502			$(new Image()).one('load', $.proxy(function(e) {
35503				element.attr('src', e.target.src);
35504				element.css('opacity', 1);
35505				this.leave('pre-loading');
35506				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
35507			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
35508		}, this));
35509	};
35510
35511	/**
35512	 * Destroys the carousel.
35513	 * @public
35514	 */
35515	Owl.prototype.destroy = function() {
35516
35517		this.$element.off('.owl.core');
35518		this.$stage.off('.owl.core');
35519		$(document).off('.owl.core');
35520
35521		if (this.settings.responsive !== false) {
35522			window.clearTimeout(this.resizeTimer);
35523			this.off(window, 'resize', this._handlers.onThrottledResize);
35524		}
35525
35526		for (var i in this._plugins) {
35527			this._plugins[i].destroy();
35528		}
35529
35530		this.$stage.children('.cloned').remove();
35531
35532		this.$stage.unwrap();
35533		this.$stage.children().contents().unwrap();
35534		this.$stage.children().unwrap();
35535
35536		this.$element
35537			.removeClass(this.options.refreshClass)
35538			.removeClass(this.options.loadingClass)
35539			.removeClass(this.options.loadedClass)
35540			.removeClass(this.options.rtlClass)
35541			.removeClass(this.options.dragClass)
35542			.removeClass(this.options.grabClass)
35543			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
35544			.removeData('owl.carousel');
35545	};
35546
35547	/**
35548	 * Operators to calculate right-to-left and left-to-right.
35549	 * @protected
35550	 * @param {Number} [a] - The left side operand.
35551	 * @param {String} [o] - The operator.
35552	 * @param {Number} [b] - The right side operand.
35553	 */
35554	Owl.prototype.op = function(a, o, b) {
35555		var rtl = this.settings.rtl;
35556		switch (o) {
35557			case '<':
35558				return rtl ? a > b : a < b;
35559			case '>':
35560				return rtl ? a < b : a > b;
35561			case '>=':
35562				return rtl ? a <= b : a >= b;
35563			case '<=':
35564				return rtl ? a >= b : a <= b;
35565			default:
35566				break;
35567		}
35568	};
35569
35570	/**
35571	 * Attaches to an internal event.
35572	 * @protected
35573	 * @param {HTMLElement} element - The event source.
35574	 * @param {String} event - The event name.
35575	 * @param {Function} listener - The event handler to attach.
35576	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
35577	 */
35578	Owl.prototype.on = function(element, event, listener, capture) {
35579		if (element.addEventListener) {
35580			element.addEventListener(event, listener, capture);
35581		} else if (element.attachEvent) {
35582			element.attachEvent('on' + event, listener);
35583		}
35584	};
35585
35586	/**
35587	 * Detaches from an internal event.
35588	 * @protected
35589	 * @param {HTMLElement} element - The event source.
35590	 * @param {String} event - The event name.
35591	 * @param {Function} listener - The attached event handler to detach.
35592	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
35593	 */
35594	Owl.prototype.off = function(element, event, listener, capture) {
35595		if (element.removeEventListener) {
35596			element.removeEventListener(event, listener, capture);
35597		} else if (element.detachEvent) {
35598			element.detachEvent('on' + event, listener);
35599		}
35600	};
35601
35602	/**
35603	 * Triggers a public event.
35604	 * @todo Remove `status`, `relatedTarget` should be used instead.
35605	 * @protected
35606	 * @param {String} name - The event name.
35607	 * @param {*} [data=null] - The event data.
35608	 * @param {String} [namespace=carousel] - The event namespace.
35609	 * @param {String} [state] - The state which is associated with the event.
35610	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
35611	 * @returns {Event} - The event arguments.
35612	 */
35613	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
35614		var status = {
35615			item: { count: this._items.length, index: this.current() }
35616		}, handler = $.camelCase(
35617			$.grep([ 'on', name, namespace ], function(v) { return v })
35618				.join('-').toLowerCase()
35619		), event = $.Event(
35620			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
35621			$.extend({ relatedTarget: this }, status, data)
35622		);
35623
35624		if (!this._supress[name]) {
35625			$.each(this._plugins, function(name, plugin) {
35626				if (plugin.onTrigger) {
35627					plugin.onTrigger(event);
35628				}
35629			});
35630
35631			this.register({ type: Owl.Type.Event, name: name });
35632			this.$element.trigger(event);
35633
35634			if (this.settings && typeof this.settings[handler] === 'function') {
35635				this.settings[handler].call(this, event);
35636			}
35637		}
35638
35639		return event;
35640	};
35641
35642	/**
35643	 * Enters a state.
35644	 * @param name - The state name.
35645	 */
35646	Owl.prototype.enter = function(name) {
35647		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
35648			if (this._states.current[name] === undefined) {
35649				this._states.current[name] = 0;
35650			}
35651
35652			this._states.current[name]++;
35653		}, this));
35654	};
35655
35656	/**
35657	 * Leaves a state.
35658	 * @param name - The state name.
35659	 */
35660	Owl.prototype.leave = function(name) {
35661		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
35662			this._states.current[name]--;
35663		}, this));
35664	};
35665
35666	/**
35667	 * Registers an event or state.
35668	 * @public
35669	 * @param {Object} object - The event or state to register.
35670	 */
35671	Owl.prototype.register = function(object) {
35672		if (object.type === Owl.Type.Event) {
35673			if (!$.event.special[object.name]) {
35674				$.event.special[object.name] = {};
35675			}
35676
35677			if (!$.event.special[object.name].owl) {
35678				var _default = $.event.special[object.name]._default;
35679				$.event.special[object.name]._default = function(e) {
35680					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
35681						return _default.apply(this, arguments);
35682					}
35683					return e.namespace && e.namespace.indexOf('owl') > -1;
35684				};
35685				$.event.special[object.name].owl = true;
35686			}
35687		} else if (object.type === Owl.Type.State) {
35688			if (!this._states.tags[object.name]) {
35689				this._states.tags[object.name] = object.tags;
35690			} else {
35691				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
35692			}
35693
35694			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
35695				return $.inArray(tag, this._states.tags[object.name]) === i;
35696			}, this));
35697		}
35698	};
35699
35700	/**
35701	 * Suppresses events.
35702	 * @protected
35703	 * @param {Array.<String>} events - The events to suppress.
35704	 */
35705	Owl.prototype.suppress = function(events) {
35706		$.each(events, $.proxy(function(index, event) {
35707			this._supress[event] = true;
35708		}, this));
35709	};
35710
35711	/**
35712	 * Releases suppressed events.
35713	 * @protected
35714	 * @param {Array.<String>} events - The events to release.
35715	 */
35716	Owl.prototype.release = function(events) {
35717		$.each(events, $.proxy(function(index, event) {
35718			delete this._supress[event];
35719		}, this));
35720	};
35721
35722	/**
35723	 * Gets unified pointer coordinates from event.
35724	 * @todo #261
35725	 * @protected
35726	 * @param {Event} - The `mousedown` or `touchstart` event.
35727	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
35728	 */
35729	Owl.prototype.pointer = function(event) {
35730		var result = { x: null, y: null };
35731
35732		event = event.originalEvent || event || window.event;
35733
35734		event = event.touches && event.touches.length ?
35735			event.touches[0] : event.changedTouches && event.changedTouches.length ?
35736				event.changedTouches[0] : event;
35737
35738		if (event.pageX) {
35739			result.x = event.pageX;
35740			result.y = event.pageY;
35741		} else {
35742			result.x = event.clientX;
35743			result.y = event.clientY;
35744		}
35745
35746		return result;
35747	};
35748
35749	/**
35750	 * Determines if the input is a Number or something that can be coerced to a Number
35751	 * @protected
35752	 * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
35753	 * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
35754	 */
35755	Owl.prototype.isNumeric = function(number) {
35756		return !isNaN(parseFloat(number));
35757	};
35758
35759	/**
35760	 * Gets the difference of two vectors.
35761	 * @todo #261
35762	 * @protected
35763	 * @param {Object} - The first vector.
35764	 * @param {Object} - The second vector.
35765	 * @returns {Object} - The difference.
35766	 */
35767	Owl.prototype.difference = function(first, second) {
35768		return {
35769			x: first.x - second.x,
35770			y: first.y - second.y
35771		};
35772	};
35773
35774	/**
35775	 * The jQuery Plugin for the Owl Carousel
35776	 * @todo Navigation plugin `next` and `prev`
35777	 * @public
35778	 */
35779	$.fn.owlCarousel = function(option) {
35780		var args = Array.prototype.slice.call(arguments, 1);
35781
35782		return this.each(function() {
35783			var $this = $(this),
35784				data = $this.data('owl.carousel');
35785
35786			if (!data) {
35787				data = new Owl(this, typeof option == 'object' && option);
35788				$this.data('owl.carousel', data);
35789
35790				$.each([
35791					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
35792				], function(i, event) {
35793					data.register({ type: Owl.Type.Event, name: event });
35794					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
35795						if (e.namespace && e.relatedTarget !== this) {
35796							this.suppress([ event ]);
35797							data[event].apply(this, [].slice.call(arguments, 1));
35798							this.release([ event ]);
35799						}
35800					}, data));
35801				});
35802			}
35803
35804			if (typeof option == 'string' && option.charAt(0) !== '_') {
35805				data[option].apply(data, args);
35806			}
35807		});
35808	};
35809
35810	/**
35811	 * The constructor for the jQuery Plugin
35812	 * @public
35813	 */
35814	$.fn.owlCarousel.Constructor = Owl;
35815
35816})(window.Zepto || window.jQuery, window, document);
35817
35818/**
35819 * AutoRefresh Plugin
35820 * @version 2.1.0
35821 * @author Artus Kolanowski
35822 * @author David Deutsch
35823 * @license The MIT License (MIT)
35824 */
35825;(function($, window, document, undefined) {
35826
35827	/**
35828	 * Creates the auto refresh plugin.
35829	 * @class The Auto Refresh Plugin
35830	 * @param {Owl} carousel - The Owl Carousel
35831	 */
35832	var AutoRefresh = function(carousel) {
35833		/**
35834		 * Reference to the core.
35835		 * @protected
35836		 * @type {Owl}
35837		 */
35838		this._core = carousel;
35839
35840		/**
35841		 * Refresh interval.
35842		 * @protected
35843		 * @type {number}
35844		 */
35845		this._interval = null;
35846
35847		/**
35848		 * Whether the element is currently visible or not.
35849		 * @protected
35850		 * @type {Boolean}
35851		 */
35852		this._visible = null;
35853
35854		/**
35855		 * All event handlers.
35856		 * @protected
35857		 * @type {Object}
35858		 */
35859		this._handlers = {
35860			'initialized.owl.carousel': $.proxy(function(e) {
35861				if (e.namespace && this._core.settings.autoRefresh) {
35862					this.watch();
35863				}
35864			}, this)
35865		};
35866
35867		// set default options
35868		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
35869
35870		// register event handlers
35871		this._core.$element.on(this._handlers);
35872	};
35873
35874	/**
35875	 * Default options.
35876	 * @public
35877	 */
35878	AutoRefresh.Defaults = {
35879		autoRefresh: true,
35880		autoRefreshInterval: 500
35881	};
35882
35883	/**
35884	 * Watches the element.
35885	 */
35886	AutoRefresh.prototype.watch = function() {
35887		if (this._interval) {
35888			return;
35889		}
35890
35891		this._visible = this._core.$element.is(':visible');
35892		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
35893	};
35894
35895	/**
35896	 * Refreshes the element.
35897	 */
35898	AutoRefresh.prototype.refresh = function() {
35899		if (this._core.$element.is(':visible') === this._visible) {
35900			return;
35901		}
35902
35903		this._visible = !this._visible;
35904
35905		this._core.$element.toggleClass('owl-hidden', !this._visible);
35906
35907		this._visible && (this._core.invalidate('width') && this._core.refresh());
35908	};
35909
35910	/**
35911	 * Destroys the plugin.
35912	 */
35913	AutoRefresh.prototype.destroy = function() {
35914		var handler, property;
35915
35916		window.clearInterval(this._interval);
35917
35918		for (handler in this._handlers) {
35919			this._core.$element.off(handler, this._handlers[handler]);
35920		}
35921		for (property in Object.getOwnPropertyNames(this)) {
35922			typeof this[property] != 'function' && (this[property] = null);
35923		}
35924	};
35925
35926	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
35927
35928})(window.Zepto || window.jQuery, window, document);
35929
35930/**
35931 * Lazy Plugin
35932 * @version 2.1.0
35933 * @author Bartosz Wojciechowski
35934 * @author David Deutsch
35935 * @license The MIT License (MIT)
35936 */
35937;(function($, window, document, undefined) {
35938
35939	/**
35940	 * Creates the lazy plugin.
35941	 * @class The Lazy Plugin
35942	 * @param {Owl} carousel - The Owl Carousel
35943	 */
35944	var Lazy = function(carousel) {
35945
35946		/**
35947		 * Reference to the core.
35948		 * @protected
35949		 * @type {Owl}
35950		 */
35951		this._core = carousel;
35952
35953		/**
35954		 * Already loaded items.
35955		 * @protected
35956		 * @type {Array.<jQuery>}
35957		 */
35958		this._loaded = [];
35959
35960		/**
35961		 * Event handlers.
35962		 * @protected
35963		 * @type {Object}
35964		 */
35965		this._handlers = {
35966			'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
35967				if (!e.namespace) {
35968					return;
35969				}
35970
35971				if (!this._core.settings || !this._core.settings.lazyLoad) {
35972					return;
35973				}
35974
35975				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
35976					var settings = this._core.settings,
35977						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
35978						i = ((settings.center && n * -1) || 0),
35979						position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
35980						clones = this._core.clones().length,
35981						load = $.proxy(function(i, v) { this.load(v) }, this);
35982
35983					while (i++ < n) {
35984						this.load(clones / 2 + this._core.relative(position));
35985						clones && $.each(this._core.clones(this._core.relative(position)), load);
35986						position++;
35987					}
35988				}
35989			}, this)
35990		};
35991
35992		// set the default options
35993		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
35994
35995		// register event handler
35996		this._core.$element.on(this._handlers);
35997	};
35998
35999	/**
36000	 * Default options.
36001	 * @public
36002	 */
36003	Lazy.Defaults = {
36004		lazyLoad: false
36005	};
36006
36007	/**
36008	 * Loads all resources of an item at the specified position.
36009	 * @param {Number} position - The absolute position of the item.
36010	 * @protected
36011	 */
36012	Lazy.prototype.load = function(position) {
36013		var $item = this._core.$stage.children().eq(position),
36014			$elements = $item && $item.find('.owl-lazy');
36015
36016		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
36017			return;
36018		}
36019
36020		$elements.each($.proxy(function(index, element) {
36021			var $element = $(element), image,
36022				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
36023
36024			this._core.trigger('load', { element: $element, url: url }, 'lazy');
36025
36026			if ($element.is('img')) {
36027				$element.one('load.owl.lazy', $.proxy(function() {
36028					$element.css('opacity', 1);
36029					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
36030				}, this)).attr('src', url);
36031			} else {
36032				image = new Image();
36033				image.onload = $.proxy(function() {
36034					$element.css({
36035						'background-image': 'url("' + url + '")',
36036						'opacity': '1'
36037					});
36038					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
36039				}, this);
36040				image.src = url;
36041			}
36042		}, this));
36043
36044		this._loaded.push($item.get(0));
36045	};
36046
36047	/**
36048	 * Destroys the plugin.
36049	 * @public
36050	 */
36051	Lazy.prototype.destroy = function() {
36052		var handler, property;
36053
36054		for (handler in this.handlers) {
36055			this._core.$element.off(handler, this.handlers[handler]);
36056		}
36057		for (property in Object.getOwnPropertyNames(this)) {
36058			typeof this[property] != 'function' && (this[property] = null);
36059		}
36060	};
36061
36062	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
36063
36064})(window.Zepto || window.jQuery, window, document);
36065
36066/**
36067 * AutoHeight Plugin
36068 * @version 2.1.0
36069 * @author Bartosz Wojciechowski
36070 * @author David Deutsch
36071 * @license The MIT License (MIT)
36072 */
36073;(function($, window, document, undefined) {
36074
36075	/**
36076	 * Creates the auto height plugin.
36077	 * @class The Auto Height Plugin
36078	 * @param {Owl} carousel - The Owl Carousel
36079	 */
36080	var AutoHeight = function(carousel) {
36081		/**
36082		 * Reference to the core.
36083		 * @protected
36084		 * @type {Owl}
36085		 */
36086		this._core = carousel;
36087
36088		/**
36089		 * All event handlers.
36090		 * @protected
36091		 * @type {Object}
36092		 */
36093		this._handlers = {
36094			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
36095				if (e.namespace && this._core.settings.autoHeight) {
36096					this.update();
36097				}
36098			}, this),
36099			'changed.owl.carousel': $.proxy(function(e) {
36100				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
36101					this.update();
36102				}
36103			}, this),
36104			'loaded.owl.lazy': $.proxy(function(e) {
36105				if (e.namespace && this._core.settings.autoHeight
36106					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
36107					this.update();
36108				}
36109			}, this)
36110		};
36111
36112		// set default options
36113		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
36114
36115		// register event handlers
36116		this._core.$element.on(this._handlers);
36117	};
36118
36119	/**
36120	 * Default options.
36121	 * @public
36122	 */
36123	AutoHeight.Defaults = {
36124		autoHeight: false,
36125		autoHeightClass: 'owl-height'
36126	};
36127
36128	/**
36129	 * Updates the view.
36130	 */
36131	AutoHeight.prototype.update = function() {
36132		var start = this._core._current,
36133			end = start + this._core.settings.items,
36134			visible = this._core.$stage.children().toArray().slice(start, end),
36135			heights = [],
36136			maxheight = 0;
36137
36138		$.each(visible, function(index, item) {
36139			heights.push($(item).height());
36140		});
36141
36142		maxheight = Math.max.apply(null, heights);
36143
36144		this._core.$stage.parent()
36145			.height(maxheight)
36146			.addClass(this._core.settings.autoHeightClass);
36147	};
36148
36149	AutoHeight.prototype.destroy = function() {
36150		var handler, property;
36151
36152		for (handler in this._handlers) {
36153			this._core.$element.off(handler, this._handlers[handler]);
36154		}
36155		for (property in Object.getOwnPropertyNames(this)) {
36156			typeof this[property] != 'function' && (this[property] = null);
36157		}
36158	};
36159
36160	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
36161
36162})(window.Zepto || window.jQuery, window, document);
36163
36164/**
36165 * Video Plugin
36166 * @version 2.1.0
36167 * @author Bartosz Wojciechowski
36168 * @author David Deutsch
36169 * @license The MIT License (MIT)
36170 */
36171;(function($, window, document, undefined) {
36172
36173	/**
36174	 * Creates the video plugin.
36175	 * @class The Video Plugin
36176	 * @param {Owl} carousel - The Owl Carousel
36177	 */
36178	var Video = function(carousel) {
36179		/**
36180		 * Reference to the core.
36181		 * @protected
36182		 * @type {Owl}
36183		 */
36184		this._core = carousel;
36185
36186		/**
36187		 * Cache all video URLs.
36188		 * @protected
36189		 * @type {Object}
36190		 */
36191		this._videos = {};
36192
36193		/**
36194		 * Current playing item.
36195		 * @protected
36196		 * @type {jQuery}
36197		 */
36198		this._playing = null;
36199
36200		/**
36201		 * All event handlers.
36202		 * @todo The cloned content removale is too late
36203		 * @protected
36204		 * @type {Object}
36205		 */
36206		this._handlers = {
36207			'initialized.owl.carousel': $.proxy(function(e) {
36208				if (e.namespace) {
36209					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
36210				}
36211			}, this),
36212			'resize.owl.carousel': $.proxy(function(e) {
36213				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
36214					e.preventDefault();
36215				}
36216			}, this),
36217			'refreshed.owl.carousel': $.proxy(function(e) {
36218				if (e.namespace && this._core.is('resizing')) {
36219					this._core.$stage.find('.cloned .owl-video-frame').remove();
36220				}
36221			}, this),
36222			'changed.owl.carousel': $.proxy(function(e) {
36223				if (e.namespace && e.property.name === 'position' && this._playing) {
36224					this.stop();
36225				}
36226			}, this),
36227			'prepared.owl.carousel': $.proxy(function(e) {
36228				if (!e.namespace) {
36229					return;
36230				}
36231
36232				var $element = $(e.content).find('.owl-video');
36233
36234				if ($element.length) {
36235					$element.css('display', 'none');
36236					this.fetch($element, $(e.content));
36237				}
36238			}, this)
36239		};
36240
36241		// set default options
36242		this._core.options = $.extend({}, Video.Defaults, this._core.options);
36243
36244		// register event handlers
36245		this._core.$element.on(this._handlers);
36246
36247		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
36248			this.play(e);
36249		}, this));
36250	};
36251
36252	/**
36253	 * Default options.
36254	 * @public
36255	 */
36256	Video.Defaults = {
36257		video: false,
36258		videoHeight: false,
36259		videoWidth: false
36260	};
36261
36262	/**
36263	 * Gets the video ID and the type (YouTube/Vimeo/vzaar only).
36264	 * @protected
36265	 * @param {jQuery} target - The target containing the video data.
36266	 * @param {jQuery} item - The item containing the video.
36267	 */
36268	Video.prototype.fetch = function(target, item) {
36269			var type = (function() {
36270					if (target.attr('data-vimeo-id')) {
36271						return 'vimeo';
36272					} else if (target.attr('data-vzaar-id')) {
36273						return 'vzaar'
36274					} else {
36275						return 'youtube';
36276					}
36277				})(),
36278				id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'),
36279				width = target.attr('data-width') || this._core.settings.videoWidth,
36280				height = target.attr('data-height') || this._core.settings.videoHeight,
36281				url = target.attr('href');
36282
36283		if (url) {
36284
36285			/*
36286					Parses the id's out of the following urls (and probably more):
36287					https://www.youtube.com/watch?v=:id
36288					https://youtu.be/:id
36289					https://vimeo.com/:id
36290					https://vimeo.com/channels/:channel/:id
36291					https://vimeo.com/groups/:group/videos/:id
36292					https://app.vzaar.com/videos/:id
36293
36294					Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
36295			*/
36296
36297			id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
36298
36299			if (id[3].indexOf('youtu') > -1) {
36300				type = 'youtube';
36301			} else if (id[3].indexOf('vimeo') > -1) {
36302				type = 'vimeo';
36303			} else if (id[3].indexOf('vzaar') > -1) {
36304				type = 'vzaar';
36305			} else {
36306				throw new Error('Video URL not supported.');
36307			}
36308			id = id[6];
36309		} else {
36310			throw new Error('Missing video URL.');
36311		}
36312
36313		this._videos[url] = {
36314			type: type,
36315			id: id,
36316			width: width,
36317			height: height
36318		};
36319
36320		item.attr('data-video', url);
36321
36322		this.thumbnail(target, this._videos[url]);
36323	};
36324
36325	/**
36326	 * Creates video thumbnail.
36327	 * @protected
36328	 * @param {jQuery} target - The target containing the video data.
36329	 * @param {Object} info - The video info object.
36330	 * @see `fetch`
36331	 */
36332	Video.prototype.thumbnail = function(target, video) {
36333		var tnLink,
36334			icon,
36335			path,
36336			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
36337			customTn = target.find('img'),
36338			srcType = 'src',
36339			lazyClass = '',
36340			settings = this._core.settings,
36341			create = function(path) {
36342				icon = '<div class="owl-video-play-icon"></div>';
36343
36344				if (settings.lazyLoad) {
36345					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
36346				} else {
36347					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
36348				}
36349				target.after(tnLink);
36350				target.after(icon);
36351			};
36352
36353		// wrap video content into owl-video-wrapper div
36354		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
36355
36356		if (this._core.settings.lazyLoad) {
36357			srcType = 'data-src';
36358			lazyClass = 'owl-lazy';
36359		}
36360
36361		// custom thumbnail
36362		if (customTn.length) {
36363			create(customTn.attr(srcType));
36364			customTn.remove();
36365			return false;
36366		}
36367
36368		if (video.type === 'youtube') {
36369			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
36370			create(path);
36371		} else if (video.type === 'vimeo') {
36372			$.ajax({
36373				type: 'GET',
36374				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
36375				jsonp: 'callback',
36376				dataType: 'jsonp',
36377				success: function(data) {
36378					path = data[0].thumbnail_large;
36379					create(path);
36380				}
36381			});
36382		} else if (video.type === 'vzaar') {
36383			$.ajax({
36384				type: 'GET',
36385				url: '//vzaar.com/api/videos/' + video.id + '.json',
36386				jsonp: 'callback',
36387				dataType: 'jsonp',
36388				success: function(data) {
36389					path = data.framegrab_url;
36390					create(path);
36391				}
36392			});
36393		}
36394	};
36395
36396	/**
36397	 * Stops the current video.
36398	 * @public
36399	 */
36400	Video.prototype.stop = function() {
36401		this._core.trigger('stop', null, 'video');
36402		this._playing.find('.owl-video-frame').remove();
36403		this._playing.removeClass('owl-video-playing');
36404		this._playing = null;
36405		this._core.leave('playing');
36406		this._core.trigger('stopped', null, 'video');
36407	};
36408
36409	/**
36410	 * Starts the current video.
36411	 * @public
36412	 * @param {Event} event - The event arguments.
36413	 */
36414	Video.prototype.play = function(event) {
36415		var target = $(event.target),
36416			item = target.closest('.' + this._core.settings.itemClass),
36417			video = this._videos[item.attr('data-video')],
36418			width = video.width || '100%',
36419			height = video.height || this._core.$stage.height(),
36420			html;
36421
36422		if (this._playing) {
36423			return;
36424		}
36425
36426		this._core.enter('playing');
36427		this._core.trigger('play', null, 'video');
36428
36429		item = this._core.items(this._core.relative(item.index()));
36430
36431		this._core.reset(item.index());
36432
36433		if (video.type === 'youtube') {
36434			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
36435				video.id + '?autoplay=1&rel=0&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
36436		} else if (video.type === 'vimeo') {
36437			html = '<iframe src="//player.vimeo.com/video/' + video.id +
36438				'?autoplay=1" width="' + width + '" height="' + height +
36439				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
36440		} else if (video.type === 'vzaar') {
36441			html = '<iframe frameborder="0"' + 'height="' + height + '"' + 'width="' + width +
36442				'" allowfullscreen mozallowfullscreen webkitAllowFullScreen ' +
36443				'src="//view.vzaar.com/' + video.id + '/player?autoplay=true"></iframe>';
36444		}
36445
36446		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
36447
36448		this._playing = item.addClass('owl-video-playing');
36449	};
36450
36451	/**
36452	 * Checks whether an video is currently in full screen mode or not.
36453	 * @todo Bad style because looks like a readonly method but changes members.
36454	 * @protected
36455	 * @returns {Boolean}
36456	 */
36457	Video.prototype.isInFullScreen = function() {
36458		var element = document.fullscreenElement || document.mozFullScreenElement ||
36459				document.webkitFullscreenElement;
36460
36461		return element && $(element).parent().hasClass('owl-video-frame');
36462	};
36463
36464	/**
36465	 * Destroys the plugin.
36466	 */
36467	Video.prototype.destroy = function() {
36468		var handler, property;
36469
36470		this._core.$element.off('click.owl.video');
36471
36472		for (handler in this._handlers) {
36473			this._core.$element.off(handler, this._handlers[handler]);
36474		}
36475		for (property in Object.getOwnPropertyNames(this)) {
36476			typeof this[property] != 'function' && (this[property] = null);
36477		}
36478	};
36479
36480	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
36481
36482})(window.Zepto || window.jQuery, window, document);
36483
36484/**
36485 * Animate Plugin
36486 * @version 2.1.0
36487 * @author Bartosz Wojciechowski
36488 * @author David Deutsch
36489 * @license The MIT License (MIT)
36490 */
36491;(function($, window, document, undefined) {
36492
36493	/**
36494	 * Creates the animate plugin.
36495	 * @class The Navigation Plugin
36496	 * @param {Owl} scope - The Owl Carousel
36497	 */
36498	var Animate = function(scope) {
36499		this.core = scope;
36500		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
36501		this.swapping = true;
36502		this.previous = undefined;
36503		this.next = undefined;
36504
36505		this.handlers = {
36506			'change.owl.carousel': $.proxy(function(e) {
36507				if (e.namespace && e.property.name == 'position') {
36508					this.previous = this.core.current();
36509					this.next = e.property.value;
36510				}
36511			}, this),
36512			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
36513				if (e.namespace) {
36514					this.swapping = e.type == 'translated';
36515				}
36516			}, this),
36517			'translate.owl.carousel': $.proxy(function(e) {
36518				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
36519					this.swap();
36520				}
36521			}, this)
36522		};
36523
36524		this.core.$element.on(this.handlers);
36525	};
36526
36527	/**
36528	 * Default options.
36529	 * @public
36530	 */
36531	Animate.Defaults = {
36532		animateOut: false,
36533		animateIn: false
36534	};
36535
36536	/**
36537	 * Toggles the animation classes whenever an translations starts.
36538	 * @protected
36539	 * @returns {Boolean|undefined}
36540	 */
36541	Animate.prototype.swap = function() {
36542
36543		if (this.core.settings.items !== 1) {
36544			return;
36545		}
36546
36547		if (!$.support.animation || !$.support.transition) {
36548			return;
36549		}
36550
36551		this.core.speed(0);
36552
36553		var left,
36554			clear = $.proxy(this.clear, this),
36555			previous = this.core.$stage.children().eq(this.previous),
36556			next = this.core.$stage.children().eq(this.next),
36557			incoming = this.core.settings.animateIn,
36558			outgoing = this.core.settings.animateOut;
36559
36560		if (this.core.current() === this.previous) {
36561			return;
36562		}
36563
36564		if (outgoing) {
36565			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
36566			previous.one($.support.animation.end, clear)
36567				.css( { 'left': left + 'px' } )
36568				.addClass('animated owl-animated-out')
36569				.addClass(outgoing);
36570		}
36571
36572		if (incoming) {
36573			next.one($.support.animation.end, clear)
36574				.addClass('animated owl-animated-in')
36575				.addClass(incoming);
36576		}
36577	};
36578
36579	Animate.prototype.clear = function(e) {
36580		$(e.target).css( { 'left': '' } )
36581			.removeClass('animated owl-animated-out owl-animated-in')
36582			.removeClass(this.core.settings.animateIn)
36583			.removeClass(this.core.settings.animateOut);
36584		this.core.onTransitionEnd();
36585	};
36586
36587	/**
36588	 * Destroys the plugin.
36589	 * @public
36590	 */
36591	Animate.prototype.destroy = function() {
36592		var handler, property;
36593
36594		for (handler in this.handlers) {
36595			this.core.$element.off(handler, this.handlers[handler]);
36596		}
36597		for (property in Object.getOwnPropertyNames(this)) {
36598			typeof this[property] != 'function' && (this[property] = null);
36599		}
36600	};
36601
36602	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
36603
36604})(window.Zepto || window.jQuery, window, document);
36605
36606/**
36607 * Autoplay Plugin
36608 * @version 2.1.0
36609 * @author Bartosz Wojciechowski
36610 * @author Artus Kolanowski
36611 * @author David Deutsch
36612 * @license The MIT License (MIT)
36613 */
36614;(function($, window, document, undefined) {
36615
36616	/**
36617	 * Creates the autoplay plugin.
36618	 * @class The Autoplay Plugin
36619	 * @param {Owl} scope - The Owl Carousel
36620	 */
36621	var Autoplay = function(carousel) {
36622		/**
36623		 * Reference to the core.
36624		 * @protected
36625		 * @type {Owl}
36626		 */
36627		this._core = carousel;
36628
36629		/**
36630		 * The autoplay timeout.
36631		 * @type {Timeout}
36632		 */
36633		this._timeout = null;
36634
36635		/**
36636		 * Indicates whenever the autoplay is paused.
36637		 * @type {Boolean}
36638		 */
36639		this._paused = false;
36640
36641		/**
36642		 * All event handlers.
36643		 * @protected
36644		 * @type {Object}
36645		 */
36646		this._handlers = {
36647			'changed.owl.carousel': $.proxy(function(e) {
36648				if (e.namespace && e.property.name === 'settings') {
36649					if (this._core.settings.autoplay) {
36650						this.play();
36651					} else {
36652						this.stop();
36653					}
36654				} else if (e.namespace && e.property.name === 'position') {
36655					//console.log('play?', e);
36656					if (this._core.settings.autoplay) {
36657						this._setAutoPlayInterval();
36658					}
36659				}
36660			}, this),
36661			'initialized.owl.carousel': $.proxy(function(e) {
36662				if (e.namespace && this._core.settings.autoplay) {
36663					this.play();
36664				}
36665			}, this),
36666			'play.owl.autoplay': $.proxy(function(e, t, s) {
36667				if (e.namespace) {
36668					this.play(t, s);
36669				}
36670			}, this),
36671			'stop.owl.autoplay': $.proxy(function(e) {
36672				if (e.namespace) {
36673					this.stop();
36674				}
36675			}, this),
36676			'mouseover.owl.autoplay': $.proxy(function() {
36677				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
36678					this.pause();
36679				}
36680			}, this),
36681			'mouseleave.owl.autoplay': $.proxy(function() {
36682				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
36683					this.play();
36684				}
36685			}, this),
36686			'touchstart.owl.core': $.proxy(function() {
36687				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
36688					this.pause();
36689				}
36690			}, this),
36691			'touchend.owl.core': $.proxy(function() {
36692				if (this._core.settings.autoplayHoverPause) {
36693					this.play();
36694				}
36695			}, this)
36696		};
36697
36698		// register event handlers
36699		this._core.$element.on(this._handlers);
36700
36701		// set default options
36702		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
36703	};
36704
36705	/**
36706	 * Default options.
36707	 * @public
36708	 */
36709	Autoplay.Defaults = {
36710		autoplay: false,
36711		autoplayTimeout: 5000,
36712		autoplayHoverPause: false,
36713		autoplaySpeed: false
36714	};
36715
36716	/**
36717	 * Starts the autoplay.
36718	 * @public
36719	 * @param {Number} [timeout] - The interval before the next animation starts.
36720	 * @param {Number} [speed] - The animation speed for the animations.
36721	 */
36722	Autoplay.prototype.play = function(timeout, speed) {
36723		this._paused = false;
36724
36725		if (this._core.is('rotating')) {
36726			return;
36727		}
36728
36729		this._core.enter('rotating');
36730
36731		this._setAutoPlayInterval();
36732	};
36733
36734	/**
36735	 * Gets a new timeout
36736	 * @private
36737	 * @param {Number} [timeout] - The interval before the next animation starts.
36738	 * @param {Number} [speed] - The animation speed for the animations.
36739	 * @return {Timeout}
36740	 */
36741	Autoplay.prototype._getNextTimeout = function(timeout, speed) {
36742		if ( this._timeout ) {
36743			window.clearTimeout(this._timeout);
36744		}
36745		return window.setTimeout($.proxy(function() {
36746			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
36747				return;
36748			}
36749			this._core.next(speed || this._core.settings.autoplaySpeed);
36750		}, this), timeout || this._core.settings.autoplayTimeout);
36751	};
36752
36753	/**
36754	 * Sets autoplay in motion.
36755	 * @private
36756	 */
36757	Autoplay.prototype._setAutoPlayInterval = function() {
36758		this._timeout = this._getNextTimeout();
36759	};
36760
36761	/**
36762	 * Stops the autoplay.
36763	 * @public
36764	 */
36765	Autoplay.prototype.stop = function() {
36766		if (!this._core.is('rotating')) {
36767			return;
36768		}
36769
36770		window.clearTimeout(this._timeout);
36771		this._core.leave('rotating');
36772	};
36773
36774	/**
36775	 * Stops the autoplay.
36776	 * @public
36777	 */
36778	Autoplay.prototype.pause = function() {
36779		if (!this._core.is('rotating')) {
36780			return;
36781		}
36782
36783		this._paused = true;
36784	};
36785
36786	/**
36787	 * Destroys the plugin.
36788	 */
36789	Autoplay.prototype.destroy = function() {
36790		var handler, property;
36791
36792		this.stop();
36793
36794		for (handler in this._handlers) {
36795			this._core.$element.off(handler, this._handlers[handler]);
36796		}
36797		for (property in Object.getOwnPropertyNames(this)) {
36798			typeof this[property] != 'function' && (this[property] = null);
36799		}
36800	};
36801
36802	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
36803
36804})(window.Zepto || window.jQuery, window, document);
36805
36806/**
36807 * Navigation Plugin
36808 * @version 2.1.0
36809 * @author Artus Kolanowski
36810 * @author David Deutsch
36811 * @license The MIT License (MIT)
36812 */
36813;(function($, window, document, undefined) {
36814	'use strict';
36815
36816	/**
36817	 * Creates the navigation plugin.
36818	 * @class The Navigation Plugin
36819	 * @param {Owl} carousel - The Owl Carousel.
36820	 */
36821	var Navigation = function(carousel) {
36822		/**
36823		 * Reference to the core.
36824		 * @protected
36825		 * @type {Owl}
36826		 */
36827		this._core = carousel;
36828
36829		/**
36830		 * Indicates whether the plugin is initialized or not.
36831		 * @protected
36832		 * @type {Boolean}
36833		 */
36834		this._initialized = false;
36835
36836		/**
36837		 * The current paging indexes.
36838		 * @protected
36839		 * @type {Array}
36840		 */
36841		this._pages = [];
36842
36843		/**
36844		 * All DOM elements of the user interface.
36845		 * @protected
36846		 * @type {Object}
36847		 */
36848		this._controls = {};
36849
36850		/**
36851		 * Markup for an indicator.
36852		 * @protected
36853		 * @type {Array.<String>}
36854		 */
36855		this._templates = [];
36856
36857		/**
36858		 * The carousel element.
36859		 * @type {jQuery}
36860		 */
36861		this.$element = this._core.$element;
36862
36863		/**
36864		 * Overridden methods of the carousel.
36865		 * @protected
36866		 * @type {Object}
36867		 */
36868		this._overrides = {
36869			next: this._core.next,
36870			prev: this._core.prev,
36871			to: this._core.to
36872		};
36873
36874		/**
36875		 * All event handlers.
36876		 * @protected
36877		 * @type {Object}
36878		 */
36879		this._handlers = {
36880			'prepared.owl.carousel': $.proxy(function(e) {
36881				if (e.namespace && this._core.settings.dotsData) {
36882					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
36883						$(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '</div>');
36884				}
36885			}, this),
36886			'added.owl.carousel': $.proxy(function(e) {
36887				if (e.namespace && this._core.settings.dotsData) {
36888					this._templates.splice(e.position, 0, this._templates.pop());
36889				}
36890			}, this),
36891			'remove.owl.carousel': $.proxy(function(e) {
36892				if (e.namespace && this._core.settings.dotsData) {
36893					this._templates.splice(e.position, 1);
36894				}
36895			}, this),
36896			'changed.owl.carousel': $.proxy(function(e) {
36897				if (e.namespace && e.property.name == 'position') {
36898					this.draw();
36899				}
36900			}, this),
36901			'initialized.owl.carousel': $.proxy(function(e) {
36902				if (e.namespace && !this._initialized) {
36903					this._core.trigger('initialize', null, 'navigation');
36904					this.initialize();
36905					this.update();
36906					this.draw();
36907					this._initialized = true;
36908					this._core.trigger('initialized', null, 'navigation');
36909				}
36910			}, this),
36911			'refreshed.owl.carousel': $.proxy(function(e) {
36912				if (e.namespace && this._initialized) {
36913					this._core.trigger('refresh', null, 'navigation');
36914					this.update();
36915					this.draw();
36916					this._core.trigger('refreshed', null, 'navigation');
36917				}
36918			}, this)
36919		};
36920
36921		// set default options
36922		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
36923
36924		// register event handlers
36925		this.$element.on(this._handlers);
36926	};
36927
36928	/**
36929	 * Default options.
36930	 * @public
36931	 * @todo Rename `slideBy` to `navBy`
36932	 */
36933	Navigation.Defaults = {
36934		nav: false,
36935		navText: [ 'prev', 'next' ],
36936		navSpeed: false,
36937		navElement: 'div',
36938		navContainer: false,
36939		navContainerClass: 'owl-nav',
36940		navClass: [ 'owl-prev', 'owl-next' ],
36941		slideBy: 1,
36942		dotClass: 'owl-dot',
36943		dotsClass: 'owl-dots',
36944		dots: true,
36945		dotsEach: false,
36946		dotsData: false,
36947		dotsSpeed: false,
36948		dotsContainer: false
36949	};
36950
36951	/**
36952	 * Initializes the layout of the plugin and extends the carousel.
36953	 * @protected
36954	 */
36955	Navigation.prototype.initialize = function() {
36956		var override,
36957			settings = this._core.settings;
36958
36959		// create DOM structure for relative navigation
36960		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
36961			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
36962
36963		this._controls.$previous = $('<' + settings.navElement + '>')
36964			.addClass(settings.navClass[0])
36965			.html(settings.navText[0])
36966			.prependTo(this._controls.$relative)
36967			.on('click', $.proxy(function(e) {
36968				this.prev(settings.navSpeed);
36969			}, this));
36970		this._controls.$next = $('<' + settings.navElement + '>')
36971			.addClass(settings.navClass[1])
36972			.html(settings.navText[1])
36973			.appendTo(this._controls.$relative)
36974			.on('click', $.proxy(function(e) {
36975				this.next(settings.navSpeed);
36976			}, this));
36977
36978		// create DOM structure for absolute navigation
36979		if (!settings.dotsData) {
36980			this._templates = [ $('<div>')
36981				.addClass(settings.dotClass)
36982				.append($('<span>'))
36983				.prop('outerHTML') ];
36984		}
36985
36986		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
36987			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
36988
36989		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
36990			var index = $(e.target).parent().is(this._controls.$absolute)
36991				? $(e.target).index() : $(e.target).parent().index();
36992
36993			e.preventDefault();
36994
36995			this.to(index, settings.dotsSpeed);
36996		}, this));
36997
36998		// override public methods of the carousel
36999		for (override in this._overrides) {
37000			this._core[override] = $.proxy(this[override], this);
37001		}
37002	};
37003
37004	/**
37005	 * Destroys the plugin.
37006	 * @protected
37007	 */
37008	Navigation.prototype.destroy = function() {
37009		var handler, control, property, override;
37010
37011		for (handler in this._handlers) {
37012			this.$element.off(handler, this._handlers[handler]);
37013		}
37014		for (control in this._controls) {
37015			this._controls[control].remove();
37016		}
37017		for (override in this.overides) {
37018			this._core[override] = this._overrides[override];
37019		}
37020		for (property in Object.getOwnPropertyNames(this)) {
37021			typeof this[property] != 'function' && (this[property] = null);
37022		}
37023	};
37024
37025	/**
37026	 * Updates the internal state.
37027	 * @protected
37028	 */
37029	Navigation.prototype.update = function() {
37030		var i, j, k,
37031			lower = this._core.clones().length / 2,
37032			upper = lower + this._core.items().length,
37033			maximum = this._core.maximum(true),
37034			settings = this._core.settings,
37035			size = settings.center || settings.autoWidth || settings.dotsData
37036				? 1 : settings.dotsEach || settings.items;
37037
37038		if (settings.slideBy !== 'page') {
37039			settings.slideBy = Math.min(settings.slideBy, settings.items);
37040		}
37041
37042		if (settings.dots || settings.slideBy == 'page') {
37043			this._pages = [];
37044
37045			for (i = lower, j = 0, k = 0; i < upper; i++) {
37046				if (j >= size || j === 0) {
37047					this._pages.push({
37048						start: Math.min(maximum, i - lower),
37049						end: i - lower + size - 1
37050					});
37051					if (Math.min(maximum, i - lower) === maximum) {
37052						break;
37053					}
37054					j = 0, ++k;
37055				}
37056				j += this._core.mergers(this._core.relative(i));
37057			}
37058		}
37059	};
37060
37061	/**
37062	 * Draws the user interface.
37063	 * @todo The option `dotsData` wont work.
37064	 * @protected
37065	 */
37066	Navigation.prototype.draw = function() {
37067		var difference,
37068			settings = this._core.settings,
37069			disabled = this._core.items().length <= settings.items,
37070			index = this._core.relative(this._core.current()),
37071			loop = settings.loop || settings.rewind;
37072
37073		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
37074
37075		if (settings.nav) {
37076			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
37077			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
37078		}
37079
37080		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
37081
37082		if (settings.dots) {
37083			difference = this._pages.length - this._controls.$absolute.children().length;
37084
37085			if (settings.dotsData && difference !== 0) {
37086				this._controls.$absolute.html(this._templates.join(''));
37087			} else if (difference > 0) {
37088				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
37089			} else if (difference < 0) {
37090				this._controls.$absolute.children().slice(difference).remove();
37091			}
37092
37093			this._controls.$absolute.find('.active').removeClass('active');
37094			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
37095		}
37096	};
37097
37098	/**
37099	 * Extends event data.
37100	 * @protected
37101	 * @param {Event} event - The event object which gets thrown.
37102	 */
37103	Navigation.prototype.onTrigger = function(event) {
37104		var settings = this._core.settings;
37105
37106		event.page = {
37107			index: $.inArray(this.current(), this._pages),
37108			count: this._pages.length,
vendor: 7,458 bytes, lines 37109-37390
37109			size: settings && (settings.center || settings.autoWidth || settings.dotsData
37110				? 1 : settings.dotsEach || settings.items)
37111		};
37112	};
37113
37114	/**
37115	 * Gets the current page position of the carousel.
37116	 * @protected
37117	 * @returns {Number}
37118	 */
37119	Navigation.prototype.current = function() {
37120		var current = this._core.relative(this._core.current());
37121		return $.grep(this._pages, $.proxy(function(page, index) {
37122			return page.start <= current && page.end >= current;
37123		}, this)).pop();
37124	};
37125
37126	/**
37127	 * Gets the current succesor/predecessor position.
37128	 * @protected
37129	 * @returns {Number}
37130	 */
37131	Navigation.prototype.getPosition = function(successor) {
37132		var position, length,
37133			settings = this._core.settings;
37134
37135		if (settings.slideBy == 'page') {
37136			position = $.inArray(this.current(), this._pages);
37137			length = this._pages.length;
37138			successor ? ++position : --position;
37139			position = this._pages[((position % length) + length) % length].start;
37140		} else {
37141			position = this._core.relative(this._core.current());
37142			length = this._core.items().length;
37143			successor ? position += settings.slideBy : position -= settings.slideBy;
37144		}
37145
37146		return position;
37147	};
37148
37149	/**
37150	 * Slides to the next item or page.
37151	 * @public
37152	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
37153	 */
37154	Navigation.prototype.next = function(speed) {
37155		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
37156	};
37157
37158	/**
37159	 * Slides to the previous item or page.
37160	 * @public
37161	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
37162	 */
37163	Navigation.prototype.prev = function(speed) {
37164		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
37165	};
37166
37167	/**
37168	 * Slides to the specified item or page.
37169	 * @public
37170	 * @param {Number} position - The position of the item or page.
37171	 * @param {Number} [speed] - The time in milliseconds for the transition.
37172	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
37173	 */
37174	Navigation.prototype.to = function(position, speed, standard) {
37175		var length;
37176
37177		if (!standard && this._pages.length) {
37178			length = this._pages.length;
37179			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
37180		} else {
37181			$.proxy(this._overrides.to, this._core)(position, speed);
37182		}
37183	};
37184
37185	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
37186
37187})(window.Zepto || window.jQuery, window, document);
37188
37189/**
37190 * Hash Plugin
37191 * @version 2.1.0
37192 * @author Artus Kolanowski
37193 * @author David Deutsch
37194 * @license The MIT License (MIT)
37195 */
37196;(function($, window, document, undefined) {
37197	'use strict';
37198
37199	/**
37200	 * Creates the hash plugin.
37201	 * @class The Hash Plugin
37202	 * @param {Owl} carousel - The Owl Carousel
37203	 */
37204	var Hash = function(carousel) {
37205		/**
37206		 * Reference to the core.
37207		 * @protected
37208		 * @type {Owl}
37209		 */
37210		this._core = carousel;
37211
37212		/**
37213		 * Hash index for the items.
37214		 * @protected
37215		 * @type {Object}
37216		 */
37217		this._hashes = {};
37218
37219		/**
37220		 * The carousel element.
37221		 * @type {jQuery}
37222		 */
37223		this.$element = this._core.$element;
37224
37225		/**
37226		 * All event handlers.
37227		 * @protected
37228		 * @type {Object}
37229		 */
37230		this._handlers = {
37231			'initialized.owl.carousel': $.proxy(function(e) {
37232				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
37233					$(window).trigger('hashchange.owl.navigation');
37234				}
37235			}, this),
37236			'prepared.owl.carousel': $.proxy(function(e) {
37237				if (e.namespace) {
37238					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
37239
37240					if (!hash) {
37241						return;
37242					}
37243
37244					this._hashes[hash] = e.content;
37245				}
37246			}, this),
37247			'changed.owl.carousel': $.proxy(function(e) {
37248				if (e.namespace && e.property.name === 'position') {
37249					var current = this._core.items(this._core.relative(this._core.current())),
37250						hash = $.map(this._hashes, function(item, hash) {
37251							return item === current ? hash : null;
37252						}).join();
37253
37254					if (!hash || window.location.hash.slice(1) === hash) {
37255						return;
37256					}
37257
37258					window.location.hash = hash;
37259				}
37260			}, this)
37261		};
37262
37263		// set default options
37264		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
37265
37266		// register the event handlers
37267		this.$element.on(this._handlers);
37268
37269		// register event listener for hash navigation
37270		$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
37271			var hash = window.location.hash.substring(1),
37272				items = this._core.$stage.children(),
37273				position = this._hashes[hash] && items.index(this._hashes[hash]);
37274
37275			if (position === undefined || position === this._core.current()) {
37276				return;
37277			}
37278
37279			this._core.to(this._core.relative(position), false, true);
37280		}, this));
37281	};
37282
37283	/**
37284	 * Default options.
37285	 * @public
37286	 */
37287	Hash.Defaults = {
37288		URLhashListener: false
37289	};
37290
37291	/**
37292	 * Destroys the plugin.
37293	 * @public
37294	 */
37295	Hash.prototype.destroy = function() {
37296		var handler, property;
37297
37298		$(window).off('hashchange.owl.navigation');
37299
37300		for (handler in this._handlers) {
37301			this._core.$element.off(handler, this._handlers[handler]);
37302		}
37303		for (property in Object.getOwnPropertyNames(this)) {
37304			typeof this[property] != 'function' && (this[property] = null);
37305		}
37306	};
37307
37308	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
37309
37310})(window.Zepto || window.jQuery, window, document);
37311
37312/**
37313 * Support Plugin
37314 *
37315 * @version 2.1.0
37316 * @author Vivid Planet Software GmbH
37317 * @author Artus Kolanowski
37318 * @author David Deutsch
37319 * @license The MIT License (MIT)
37320 */
37321;(function($, window, document, undefined) {
37322
37323	var style = $('<support>').get(0).style,
37324		prefixes = 'Webkit Moz O ms'.split(' '),
37325		events = {
37326			transition: {
37327				end: {
37328					WebkitTransition: 'webkitTransitionEnd',
37329					MozTransition: 'transitionend',
37330					OTransition: 'oTransitionEnd',
37331					transition: 'transitionend'
37332				}
37333			},
37334			animation: {
37335				end: {
37336					WebkitAnimation: 'webkitAnimationEnd',
37337					MozAnimation: 'animationend',
37338					OAnimation: 'oAnimationEnd',
37339					animation: 'animationend'
37340				}
37341			}
37342		},
37343		tests = {
37344			csstransforms: function() {
37345				return !!test('transform');
37346			},
37347			csstransforms3d: function() {
37348				return !!test('perspective');
37349			},
37350			csstransitions: function() {
37351				return !!test('transition');
37352			},
37353			cssanimations: function() {
37354				return !!test('animation');
37355			}
37356		};
37357
37358	function test(property, prefixed) {
37359		var result = false,
37360			upper = property.charAt(0).toUpperCase() + property.slice(1);
37361
37362		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
37363			if (style[property] !== undefined) {
37364				result = prefixed ? property : true;
37365				return false;
37366			}
37367		});
37368
37369		return result;
37370	}
37371
37372	function prefixed(property) {
37373		return test(property, true);
37374	}
37375
37376	if (tests.csstransitions()) {
37377		/* jshint -W053 */
37378		$.support.transition = new String(prefixed('transition'))
37379		$.support.transition.end = events.transition.end[ $.support.transition ];
37380	}
37381
37382	if (tests.cssanimations()) {
37383		/* jshint -W053 */
37384		$.support.animation = new String(prefixed('animation'))
37385		$.support.animation.end = events.animation.end[ $.support.animation ];
37386	}
37387
37388	if (tests.csstransforms()) {
37389		/* jshint -W053 */
37390		$.support.transform = new String(prefixed('transform'));
37391		$.support.transform3d = tests.csstransforms3d();
37392	}
37393
37394})(window.Zepto || window.jQuery, window, document);
37395
37396/* Global */
37397var theplayer;
37398var wWidth = $(window).width();
37399var wHeight = $(window).height();
37400
37401var frontendMaster = new function () {
37402
37403    this.init = function () {
37404        frontendMaster.accessoriesSlider();
37405        frontendMaster.topNavigation();
37406        frontendMaster.interchangeImages();
37407        frontendMaster.bootstrapFormHelpers();
37408        frontendMaster.downloadButtonFix(); 
37409        frontendMaster.getInTouchBanner();
37410        frontendMaster.latest3News();
37411        //frontendMaster.singleItemCarousel();
37412        frontendMaster.wholeWideCarousel();
37413        frontendMaster.commentsSlider();
37414        frontendMaster.productGallery();
37415        frontendMaster.simpleSlider();
37416        frontendMaster.productFiltersGroup();
37417        frontendMaster.productTableTabs();
37418        frontendMaster.productAccessoriesGallery();
37419    };
37420
37421
37422    this.accessoriesSlider = function () {
37423        var owl = $('.accessories-slider');
37424        if (owl.length > 0)
37425        {
37426            owl.owlCarousel({
37427                loop: false,
37428                margin: 10,
37429                navRewind: false,
37430                rewind: false,
37431                nav: true,
37432                dots: false,
37433                responsive: {
37434                    0: {
37435                        items: 1
37436                    },
37437                    600: {
37438                        items: 3
37439                    },
37440                    1000: {
37441                        items: 6
37442                    }
37443                }
37444            });
37445        }
37446       
37447    }
37448
37449
37450    this.interchangeImages = function () {
37451        /* Markup example: 5:2 or 8:5 aspect ratio,
37452        <div class="is-fullpage interchange-images" data-image-sm="http://placehold.it/640x480" data-image-md="http://placehold.it/1024x410" data-image-lg="./images/Topbillede-1680x480-5.jpg" data-image-sm-fullpage="http://placehold.it/640x480" data-image-md-fullpage="http://placehold.it/1024x640" data-image-lg-fullpage="http://placehold.it/1920x1200">
37453        */
37454        //Dependency enquire.js http://wicky.nillia.ms/enquire.js/#v2.0.0
37455        var querySm = "screen and (min-width:0px) and (max-width:767px)";
37456        var queryMd = "screen and (min-width:768px) and (max-width:1024px)";
37457        var queryLg = "screen and (min-width:1025px)";
37458        //interchange responsive images for different screens sizes
37459        $(".interchange-images").each(function (intIndex) {
37460            var thisModule = $(this);
37461            var imageUrlSm = $(this).attr('data-image-sm');
37462            var imageUrlMd = $(this).attr('data-image-md');
37463            var imageUrlLg = $(this).attr('data-image-lg');
37464            var imageUrlSmFullpage = $(this).attr('data-image-sm-fullpage');
37465            var imageUrlMdFullpage = $(this).attr('data-image-md-fullpage');
37466            var imageUrlLgFullpage = $(this).attr('data-image-lg-fullpage');
37467            //Load normal or fullpage bg images
37468            if ($(thisModule).hasClass("is-fullpage-slider")) {
37469                enquire
37470                    .register(querySm, {
37471                    match: function () {
37472                        //console.log("SMALL handler 1 matched");
37473                        $(thisModule).css("background-image", "url(" + imageUrlSmFullpage + ")");
37474                    },
37475                    unmatch: function () {
37476                    }
37477                })
37478                    .register(queryMd, {
37479                    match: function () {
37480                        //console.log("MEDIUM handler 2 matched");
37481                        $(thisModule).css("background-image", "url(" + imageUrlMdFullpage + ")");
37482                    },
37483                    unmatch: function () {
37484                    }
37485                })
37486                    .register(queryLg, {
37487                    match: function () {
37488                        //console.log("LARGE handler 3 matched");
37489                        $(thisModule).css("background-image", "url(" + imageUrlLgFullpage + ")");
37490                    },
37491                    unmatch: function () {
37492                    }
37493                }, true);
37494            }
37495            else {
37496                enquire
37497                    .register(querySm, {
37498                    match: function () {
37499                        //console.log("SMALL handler 1 matched");
37500                        $(thisModule).css("background-image", "url(" + imageUrlSm + ")");
37501                    },
37502                    unmatch: function () {
37503                    }
37504                })
37505                    .register(queryMd, {
37506                    match: function () {
37507                        //console.log("MEDIUM handler 2 matched");
37508                        $(thisModule).css("background-image", "url(" + imageUrlMd + ")");
37509                    },
37510                    unmatch: function () {
37511                    }
37512                })
37513                    .register(queryLg, {
37514                    match: function () {
37515                        //console.log("LARGE handler 3 matched");
37516                        $(thisModule).css("background-image", "url(" + imageUrlLg + ")");
37517                    },
37518                    unmatch: function () {
37519                    }
37520                }, true);
37521            }
37522            //fadein...
37523            $(thisModule).addClass("loaded");
37524        });
37525    };
37526
37527    this.singleItemCarousel = function () {
37528        //Requires Slick slider
37529        $('.single-item-carousel').slick({
37530            dots: true,
37531            infinite: true,
37532            speed: 400,
37533            lazyLoad: 'ondemand',
37534            autoplay: true,
37535            autoplaySpeed: 3000,
37536            accessibility: true,
37537            cssEase: 'easeOutBack',
37538            prevArrow: '<button class="btn prev" aria-label="previous" data-role="none" type="button"><i class="fa fa-chevron-left"></i></button>',
37539            nextArrow: '<button class="btn next" aria-label="next" data-role="none" type="button"><i class="fa fa-chevron-right"></i></button>',
37540            pauseOnHover: false
37541        });
37542    };
37543
37544    this.productGallery = function () {
37545        $('.product-gallery').royalSlider({
37546            autoHeight: true,
37547            arrowsNav: true,
37548            arrowsNavAutoHide: true,
37549            arrowsNavHideOnTouch: false,
37550            keyboardNavEnabled: true,
37551            fadeinLoadedSlide: true,
37552            controlNavigationSpacing: 0,
37553            controlNavigation: 'thumbnails',
37554            imageScaleMode: 'none',
37555            imageAlignCenter: true,
37556            loop: false,
37557            loopRewind: true,
37558            navigateByClick: true,
37559            numImagesToPreload: 2,
37560            usePreloader: true,
37561            slidesSpacing: 0,
37562            fullscreen: {
37563                enabled: true,
37564                keyboardNav: true,
37565                nativeFS: true
37566            },
37567            thumbs: {
37568                autoCenter: false,
37569                fitInViewPort: true,
37570                spacing: 4
37571            }
37572        });
37573    };
37574
37575    this.simpleSlider = function () {
37576        var slider = $('.simple-slider');
37577        if (slider.length > 0) {
37578
37579            $('.simple-slider').royalSlider({
37580                autoHeight: true,
37581                arrowsNav: true,
37582                arrowsNavAutoHide: true,
37583                arrowsNavHideOnTouch: false,
37584                keyboardNavEnabled: true,
37585                fadeinLoadedSlide: true,
37586                controlNavigationSpacing: 0,
37587                controlNavigation: 'thumbnails',
37588                imageScaleMode: 'none',
37589                imageAlignCenter: true,
37590                loop: false,
37591                loopRewind: true,
37592                navigateByClick: false,
37593                numImagesToPreload: 2,
37594                usePreloader: true,
37595                slidesSpacing: 0,
37596                fullscreen: {
37597                    enabled: true,
37598                    keyboardNav: true,
37599                    nativeFS: true
37600                },
37601                thumbs: {
37602                    autoCenter: false,
37603                    fitInViewPort: true,
37604                    spacing: 4
37605                }
37606            });
37607
37608        }
37609    };
37610
37611    this.loadImagesCommentsSlider = function () {
37612        var screenWidth = $(window).width();
37613        //console.log(screenWidth);
37614        // You may change image URL by modifying rsImg sources before slider initialization
37615        // Loop over each a tag and populate the right size of image....
37616        var items = $("#customers-slider .rsImg"), itemsNumber = items.length, state = "src";
37617        if (screenWidth < 640) {
37618            items.each(function (intIndex) {
37619                var image = $(this).parent().attr('data-image-xs');
37620                $(this).attr(state, image);
37621            });
37622        }
37623        else {
37624            items.each(function (intIndex) {
37625                var image = $(this).parent().attr('data-image-md');
37626                $(this).attr(state, image);
37627            });
37628        }
37629        //If only one item, add class to slider
37630        if (itemsNumber < 2) {
37631            $("#customers-slider").addClass("no-thumbnails");
37632        }
37633    };
37634    this.commentsSlider = function () {
37635        frontendMaster.loadImagesCommentsSlider();
37636        $('#customers-slider').royalSlider({
37637            controlNavigation: 'thumbnails',
37638            autoScaleSlider: false,
37639            autoScaleSliderWidth: 1500,
37640            autoScaleSliderHeight: 480,
37641            loop: true,
37642            imageScaleMode: 'none',
37643            navigateByClick: true,
37644            numImagesToPreload: 2,
37645            arrowsNav: false,
37646            arrowsNavAutoHide: false,
37647            arrowsNavHideOnTouch: false,
37648            keyboardNavEnabled: true,
37649            fadeinLoadedSlide: true,
37650            globalCaption: true,
37651            globalCaptionInside: true,
37652            slidesSpacing: 0,
37653            thumbs: {
37654                //appendSpan: true,
37655                arrows: false,
37656                firstMargin: true,
37657                paddingTop: 0,
37658                spacing: 15
37659            }
37660        });
37661        var slider = $("#customers-slider.royalSlider").data("royalSlider");
37662        //prev + next custom btns
37663        $("#customers-slider + .custom-btns .prev-btn").click(function () {
37664            slider.prev();
37665        });
37666        $("#customers-slider + .custom-btns .next-btn").click(function () {
37667            slider.next();
37668        });
37669        //fadein when is loaded...
37670        $("#customers-slider").addClass("on");
37671    };
37672    this.downloadButtonFix = function () {
37673        //hey markup from RTE is &/%/&%/, here is a fix
37674        $(".download").each(function (intIndex) {
37675            $(this).find("a").addClass("hd-btn btn-1 btn-1c btn-md");
37676        });
37677        //extra fix for icons buttons
37678        $(".hd-btn.btn-1.btn-1c").each(function (intIndex) {
37679            $(this).find("i").parent().addClass("btn-icon");
37680        });
37681    };
37682    this.lazyloadingImages = function () {
37683        //requires the jquery.lazyload.min.js plugin
37684        //<img class="lazy" data-original="img/example.jpg" width="765" height="574">
37685        $("img.lazy").lazyload({
37686            effect: "fadeIn"
37687        });
37688    };
37689    this.productFiltersGroup = function () {
37690        $(".product-filters-group h3").click(function () {
37691            $(this).closest(".product-filters-group").toggleClass("opened");
37692        });
37693    };
37694    this.wholeWideCarousel = function () {
37695        $('.whole-wide-carousel').slick({
37696            dots: false,
37697            infinite: true,
37698            speed: 300,
37699            slidesToShow: 3,
37700            slidesToScroll: 1,
37701            lazyLoad: 'ondemand',
37702            autoplay: true,
37703            autoplaySpeed: 2000,
37704            prevArrow: '<button class="btn prev" aria-label="previous" data-role="none" type="button"><i class="fa fa-chevron-left"></i></button>',
37705            nextArrow: '<button class="btn next" aria-label="next" data-role="none" type="button"><i class="fa fa-chevron-right"></i></button>',
37706            responsive: [
37707                {
37708                    breakpoint: 1024,
37709                    settings: {
37710                        slidesToShow: 3,
37711                        slidesToScroll: 3,
37712                        infinite: true,
37713                        dots: false
37714                    }
37715                },
37716                {
37717                    breakpoint: 600,
37718                    settings: {
37719                        slidesToShow: 2,
37720                        slidesToScroll: 2,
37721                        dots: false
37722                    }
37723                },
37724                {
37725                    breakpoint: 480,
37726                    settings: {
37727                        slidesToShow: 1,
37728                        slidesToScroll: 1,
37729                        dots: false
37730                    }
37731                }
37732            ]
37733        });
37734        //fade in when ready...
37735        $(".whole-wide-carousel").addClass("ready");
37736    };
37737    this.latest3News = function () {
37738        //on hover open news box
37739        $(".no-touch .latest-3-news .news-box").mouseenter(function () {
37740            $(this).parent().addClass("hover");
37741            $(this).parent().siblings().removeClass("hover");
37742        });
37743        //open the first newsbox by default
37744        $(".no-touch .latest-3-news .col-md-12 + .col-md-6").addClass("hover");
37745    };
37746    this.topHeaderScroll = function () {
37747        
37748        if (!$('html').hasClass('lt-ie9')) {
37749            //Make the top header slimmer when scrolled pass by it
37750            function yScroll() {
37751                var pagetop = $("#top"), yPos = window.pageYOffset;
37752                if (yPos > 30) {
37753                    pagetop.addClass("slim-header");
37754                }
37755                else {
37756                    pagetop.removeClass("slim-header");
37757                }
37758            }
37759            if ($('html').hasClass("no-touch")) {
37760                window.addEventListener("scroll", yScroll);
37761            }
37762        }
37763    };
37764    this.topHeaderMegadropdown = function () {
37765        //open megadropdown
37766        // add .non-dropdown-trigger for links that do not need to open a dropdown
37767        $("#desktop-nav-01 > li > a").click(function () {
37768            var subnav = $(this).attr("data-dropdown-id");
37769            if (subnav != '') {
37770                //if data-dropdown-id is not empty, open its dropdown
37771                subnav = "#" + subnav;
37772                $(subnav).slideToggle("fast"); //open active dropdown
37773                $(subnav).siblings().slideUp("fast"); //closing megadropdowns
37774                $(this).parent().siblings().removeClass("active"); //remove .active from all sibling links
37775                $(this).parent().toggleClass("active"); //add active class
37776                return false;
37777            }
37778        });
37779        2//close all subnavs on .close-subnav click
37780        $(".close-subnav").click(function () {
37781            $("#mega-dropdown > div > div").slideUp("fast");
37782            $("#desktop-nav-01 > li").removeClass("active");
37783            return false;
37784        });
37785    };
37786    this.mobileMenu = function () {
37787        //Mobile Menu.....................................
37788        $('.burger-btn').click(function () {
37789            $(this).toggleClass('open');
37790            $("#top, html").toggleClass('mobilemenu-open');
37791        });
37792        //open/close mobile menu dropdowns...
37793        $("#mobile-nav .has-children > a").click(function () {
37794            //open close dropdowns
37795            $(this).parent().toggleClass("active");
37796            $(this).toggleClass("active");
37797            //close siblings dropdowns
37798            $(this).parent().siblings().removeClass("active");
37799            return false;
37800        });
37801    };
37802    this.topNavigation = function () {
37803        frontendMaster.topHeaderScroll();
37804        frontendMaster.topHeaderMegadropdown();
37805        frontendMaster.mobileMenu();
37806    };
37807    this.bootstrapFormHelpers = function () {
37808        //requires bootstrap select dependency: (http://silviomoreto.github.io/bootstrap-select/)
37809        //Enable mobile scrolling. This enables the device's native menu for select menus.
37810        if (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
37811            $('.selectpicker').selectpicker('mobile');
37812        }
37813        else {
37814            $('.selectpicker').selectpicker();
37815        }
37816    };
37817    this.getInTouchBanner = function () {
37818        //kontakt form
37819        $('.open-contact-form').click(function () {
37820            //open contact form + hide some buttons...
37821            $(this).closest(".get-in-touch-banner").toggleClass("open-form");
37822            $(".get-in-touch-banner + #contact-form").slideToggle("fast");
37823        });
37824        //close kontakt form
37825        $('.get-in-touch-banner .fa.fa-times, .get-in-touch-banner .close-btn').click(function () {
37826            $(this).closest(".get-in-touch-banner").removeClass("open-form");
37827            $(".get-in-touch-banner + #contact-form").slideUp("fast");
37828            return false;
37829        });
37830    };
37831
37832    this.productTableTabs = function () {
37833        // Only trigger on dynamic product pages
37834        $(".product-module").each(function () {
37835            $currentModule = $(this);
37836
37837            // Find the table with tabs container
37838            $currentModule.find(".product-tab-list").each(function () {
37839                $currentTabList = $(this);
37840
37841                // Setup tabs clicks ->
37842                // Get references to both the button, and the content which should be linked to the button when clicked
37843                var $tabButtons = $currentTabList.find(".tab-button-container button");
37844                var $tabContent = $currentTabList.find(".tab-content-list .tab-container");
37845
37846                $tabButtons.on("click", function (evt) {
37847                    evt.preventDefault();
37848                    var $clickedButton = $(this);
37849
37850                    // Which no button has been clicked. The first? (index 0) or perhaps the second (index 1) ...
37851                    var targetIndex = $tabButtons.index($clickedButton);
37852
37853                    // Remove active class on all buttons and content containers
37854                    // Then add it again on the selected. Start with content, as users eyes will have focus on it ..
37855                    $tabContent.removeClass("active");
37856                    $($tabContent[targetIndex]).addClass("active");
37857
37858                    $tabButtons.removeClass("active");
37859                    $clickedButton.addClass("active");
37860                });
37861
37862                // Setup mm/inch toggle ->
37863                var $unitButtons = $currentTabList.find(".unit-button-container button");
37864                $unitButtons.on("click", function (evt) {
37865                    evt.preventDefault();
37866                    var $clickedButton = $(this);
37867                    var target = $clickedButton.data("unittype-target");
37868                    var unitContainers = $tabContent.find("span[data-unittype]");
37869                    unitContainers.hide();
37870                    unitContainers.filter("[data-unittype=" + target + "]").show();
37871
37872                    $unitButtons.removeClass("active");
37873                    $clickedButton.addClass("active");
37874                });
37875            });
37876        });
37877    };
37878
37879    // This will toggle the larger infobox for each accessory of a product when clicked
37880    this.productAccessoriesGallery = function () {
37881        $(".product-module .accessories-module").each(function () {
37882            // Settings
37883            $accessoryModule = $(this);
37884            animationSpeed = 800;
37885
37886            // Find the list of thumbnails
37887            var $accessoryThumbnails = $accessoryModule.find(".item"); 
37888
37889            // Find the container for the thumbnails
37890            var $container = $accessoryModule.find(".more-info-container > .container");
37891
37892            // When a thumbnail is clicked ..
37893            $accessoryThumbnails.on("click", function () {
37894                $clickedAccessory = $(this);
37895
37896                if (!$clickedAccessory.hasClass('active')) {
37897
37898                    // Find its index in the list
37899                    var targetIndex = $accessoryThumbnails.index($clickedAccessory);
37900                
37901                    // Find the list with the complete content for each accessory
37902                    var $accessoriesContent = $accessoryModule.find(".more-info-list > li");
37903                    var $selectedAccessoryContent = $($accessoriesContent[targetIndex]);
37904
37905                    // Prepare callback for opening the clicked box - we just need to ensure any opened boxes are gently closed first
37906                    var fnShowActiveAccessory = function () {
37907                        // Set inactive on all contentboxes
37908                        $accessoriesContent.removeClass("active");
37909
37910                        // Set active on contentbox which matches clicked thumbnail
37911                        $selectedAccessoryContent.addClass("active");
37912
37913                        // Operations has been in the hidden until now - show the result
37914                        $container.slideDown(animationSpeed)
37915                    };
37916
37917                    // If container is already open, close it before opening the clicked item
37918                    if ($container.is(":visible"))
37919                        $container.slideUp(fnShowActiveAccessory);
37920                    else
37921                        fnShowActiveAccessory();
37922
37923          2          // Hook up the close button
37924                    $selectedAccessoryContent.find(".close").on("click", function () {
37925                        $container.slideUp(function () {
37926                            $selectedAccessoryContent.removeClass("active");
37927                            $clickedAccessory.removeClass("active");
37928                        });
37929                    });
37930
37931                    // Deselect the current selected thumbnail and set the clicked one to active
37932                    $accessoryThumbnails.removeClass("active");
37933                    $clickedAccessory.addClass("active");
37934                }
37935            });
37936        });
37937    }
37938};
37939$(document).ready(function () {
37940    frontendMaster.init();
37941});
37942//# sourceMappingURL=frontend.js.map
37943var backendMaster = new function () {
37944    this.init = function () {
37945        this.ensureCompatibility();
37946        this.postFormByAjax();
37947        this.setupUmbracoForms();
37948        this.loadMoreImage();
37949        this.cookieDisclaimer();
37950        this.internalRedirectOnPage();
37951        this.parallaxScrolling();
37952    };
37953    this.parallaxScrolling = function () {
37954
37955        if ($("html.no-touch").length > 0) {
37956            var controller = new ScrollMagic.Controller({
37957                globalSceneOptions: {
37958                    triggerHook: 'onLeave'
37959                }
37960            });
37961            var slides = document.querySelectorAll(".parallaxScrolling");
37962            // create scene for every slide
37963            for (var i = 0; i < slides.length; i++) {
37964                new ScrollMagic.Scene({
37965                    triggerElement: slides[i]
37966                })
37967                .setPin(slides[i])
37968                .addTo(controller);
37969            }
37970        }
37971
37972    },
37973        this.internalRedirectOnPage = function () {
37974            $(document).on('click', 'a[href^="#"]', function (e) {
37975                // target element id
37976                var id = $(this).attr('href');
37977                // target element
37978                var $id = $(id);
37979                if ($id.length === 0) {
37980                    return;
37981                }
37982                // prevent standard hash navigation (avoid blinking in IE)
37983                e.preventDefault();
37984                // top position relative to the document
37985                var pos = $(id).offset().top;
37986                // animated top scrolling
37987                $('body, html').animate({ scrollTop: pos });
37988            });
37989        },
37990        this.cookieDisclaimer = function () {
37991            $("#cookie-div button").click(function () {
37992                document.cookie = "showcookies=0;path=/";
37993                $("#cookie-div").remove();
37994            });
37995            window.onload = function () {
37996                window.onscroll = function () {
37997                    if ($(window).scrollTop() > $(document).height() - $(window).height() - $("footer").height()) {
37998                        $("#cookie-div").addClass("scrollactive");
37999                    }
38000                    else if ($("footer").position().top <= $(window).height()) {
38001                        $("#cookie-div").addClass("scrollactive");
38002                    }
38003                    else {
38004                        $("#cookie-div").removeClass("scrollactive");
38005                    }
38006                };
38007                window.onscroll();
38008            };
38009        },
38010        this.loadMoreImage = function () {
38011            $(".loadMoreImage").click(function () {
38012                var items = $(this).parent().find(".otherImages").slice(0, 8);
38013                items.fadeIn();
38014                items.removeClass("otherImages");
38015                if ($(".otherImages").length == 0) {
38016                    $(".loadMoreImage").hide();
38017                }
38018            });
38019        };
38020    this.postFormByAjax = function () {
38021        $(".call-to-action-banner form").submit(function (e) {
38022            e.preventDefault();
38023            var form = $(this);
38024            console.log("tetser");
38025            var service = $(this).data("api");
38026            var url = "/umbraco/api/" + service; // the script where you handle the form input.
38027            if (form.valid()) {
38028                $.ajax({
38029                    type: "POST",
38030                    url: url,
38031                    data: $(this).serialize(),
38032                    success: function (data) {
38033                        form.fadeOut();
38034                        form.parent().parent().find(".signUpMessage").fadeIn();
38035                    }
38036                });
38037            }
38038            return false; // avoid to execute the actual submit of the form.
38039        });
38040    };
38041    this.setupUmbracoForms = function () {
38042        // Will only execute, on found elements
38043        // AJAX POST, instead of page-reload
38044        $(".contour form").submit(function (evt) {
38045            var form = $(this);
38046            // Prevent browser from changing page
38047            evt.preventDefault();
38048            // Validate user input (based on settings from backend)
38049            var isValid = true;
38050            form.find(".textfield.mandatory input[type=text]").each(function (index, input) {
38051                input = $(input);
38052                if (input.val().trim() == "") {
38053                    input.css("border", "1px solid Red");
38054                    isValid = false;
38055                }
38056            });
38057            if (!isValid)
38058                return false;
38059            // Take user data and serialize it
38060            var data = form.serialize();
38061            // POST to the server (with transitions)
38062            // Replace content of form with a loading-spinner and setup for showing the confirmation message
38063            $.post(form.attr("action"), data, function (response) {
38064                // "response" is the complete HTML markup for a page redirect
38065                //var confirmationMessage = $(response).find(".contourMessageOnSubmit");
38066                // Save of form is done, show confirmation to user
38067                form.fadeOut();
38068                form.parent().parent().find(".signUpMessage").fadeIn();
38069            });
38070            return false;
38071        });
38072    };
38073    this.searchByQueryString = function () {
38074        setTimeout(function () {
38075            var searchFor = backendMaster.getQueryString("search");
38076            if (searchFor != "" && typeof google !== 'undefined' && google != undefined && google.search != undefined) {
38077                var element = google.search.cse.element.getElement('searchresults-only0');
38078                if (element == null) {
38079                }
38080                else if (searchFor == '') {
38081                    element.clearAllResults();
38082                }
38083                else {
38084                    // Is the first search? Then move container to the requesting form
38085                    if ($("#searchResults").length && $("#searchResults:visible"))
38086                        $("#searchResults").appendTo(".searchResultContainer").show();
38087                    // Ask Google to show results
38088                    element.execute(searchFor);
38089                }
38090            }
38091        }, 1000);
38092    };
38093    this.startSearch = function (frmSender) {
38094        // Take searched keyword
38095        var input = frmSender.getElementsByTagName("input")[0];
38096        // Take CSE element (<<gcse:searchresults-only></gcse:searchresults-only>)
38097        if (searchFor != "" && typeof google !== 'undefined' && google != undefined && google.search != undefined) {
38098            var element = google.search.cse.element.getElement('searchresults-only0');
38099            if (element == null) {
38100            }
38101            else if (input.value == '') {
38102                element.clearAllResults();
38103            }
38104            else {
38105                // Is the first search? Then move container to the requesting form
38106                if ($("#searchResults").length && $("#searchResults:visible"))
38107                    $("#searchResults").appendTo(".searchResultContainer").show();
38108                // Ask Google to show results
38109                element.execute(input.value);
38110            }
38111        }
38112        return false;
38113    };
38114    this.getQueryString = function (name) {
38115        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
38116        var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search);
38117        return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
38118    };
38119    /* Feature detection and fixes */
38120    this.ensureCompatibility = function () {
38121        // Simulate placeholder behavoir in browsers without support for it
38122        if (Helper && !Helper.nativePlaceholderSupport()) {
38123            $("input[placeholder]").each(function () {
38124                if ($(this).val() == '')
38125                    $(this).val($(this).attr("placeholder"));
38126                $(this).addClass('placeholder');
38127            }).bind('focus', function () {
38128                if ($(this).val() == $(this).attr('placeholder')) {
38129                    $(this).val('').removeClass('placeholder');
38130                }
38131            }).bind('blur', function () {
38132                if ($(this).val() == '') {
38133                    $(this).val($(this).attr("placeholder")).addClass('placeholder');
38134                }
38135            });
38136        }
38137    };
38138};
38139$(document).ready(function () {
38140    backendMaster.init();
38141});
38142//# sourceMappingURL=backend.js.map
38143(function () {
38144
38145	var settings = {
38146		button: '#back-to-top',
38147		text: '',
38148		min: 60,
38149		fadeIn: 400,
38150		fadeOut: 400,
38151		scrollSpeed: 800,
38152		easingType: 'easeInOutExpo'
38153	}
38154
38155	$('body').append('<a href="#" id="' + settings.button.substring(1) + '" title="' + settings.text + '">' + settings.text + '</a>');
38156
38157	$(settings.button).click(function (e) {
38158		$('html, body').animate({ scrollTop: 0 }, settings.scrollSpeed, settings.easingType);
38159		e.preventDefault();
38160	});
38161
38162	$(window).scroll(function () {
38163		var position = $(window).scrollTop();
38164
38165        if (position > settings.min) {
38166            $(settings.button).addClass("active");
38167        }
38168        else {
38169            $(settings.button).removeClass("active");
38170        }
38171	});
38172
38173})();

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