OSDN Git Service

[TMP] before create Console service
[eos/zephyr.git] / front-end / dist / bundle.js
1 /******/ (function(modules) { // webpackBootstrap
2 /******/        // The module cache
3 /******/        var installedModules = {};
4
5 /******/        // The require function
6 /******/        function __webpack_require__(moduleId) {
7
8 /******/                // Check if module is in cache
9 /******/                if(installedModules[moduleId])
10 /******/                        return installedModules[moduleId].exports;
11
12 /******/                // Create a new module (and put it into the cache)
13 /******/                var module = installedModules[moduleId] = {
14 /******/                        exports: {},
15 /******/                        id: moduleId,
16 /******/                        loaded: false
17 /******/                };
18
19 /******/                // Execute the module function
20 /******/                modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21
22 /******/                // Flag the module as loaded
23 /******/                module.loaded = true;
24
25 /******/                // Return the exports of the module
26 /******/                return module.exports;
27 /******/        }
28
29
30 /******/        // expose the modules object (__webpack_modules__)
31 /******/        __webpack_require__.m = modules;
32
33 /******/        // expose the module cache
34 /******/        __webpack_require__.c = installedModules;
35
36 /******/        // __webpack_public_path__
37 /******/        __webpack_require__.p = "";
38
39 /******/        // Load entry module and return exports
40 /******/        return __webpack_require__(0);
41 /******/ })
42 /************************************************************************/
43 /******/ ([
44 /* 0 */
45 /***/ function(module, exports, __webpack_require__) {
46
47         __webpack_require__(1);
48         __webpack_require__(3);
49         __webpack_require__(4);
50         __webpack_require__(6);
51         __webpack_require__(8);
52         __webpack_require__(9);
53         __webpack_require__(10);
54         __webpack_require__(11);
55         __webpack_require__(12);
56         __webpack_require__(13);
57         __webpack_require__(14);
58         __webpack_require__(15);
59         __webpack_require__(16);
60         __webpack_require__(17);
61         __webpack_require__(18);
62         __webpack_require__(19);
63         __webpack_require__(20);
64         __webpack_require__(21);
65
66
67 /***/ },
68 /* 1 */
69 /***/ function(module, exports, __webpack_require__) {
70
71         __webpack_require__(2);
72         module.exports = angular;
73
74
75 /***/ },
76 /* 2 */
77 /***/ function(module, exports) {
78
79         /**
80          * @license AngularJS v1.4.8
81          * (c) 2010-2015 Google, Inc. http://angularjs.org
82          * License: MIT
83          */
84         (function(window, document, undefined) {'use strict';
85
86         /**
87          * @description
88          *
89          * This object provides a utility for producing rich Error messages within
90          * Angular. It can be called as follows:
91          *
92          * var exampleMinErr = minErr('example');
93          * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
94          *
95          * The above creates an instance of minErr in the example namespace. The
96          * resulting error will have a namespaced error code of example.one.  The
97          * resulting error will replace {0} with the value of foo, and {1} with the
98          * value of bar. The object is not restricted in the number of arguments it can
99          * take.
100          *
101          * If fewer arguments are specified than necessary for interpolation, the extra
102          * interpolation markers will be preserved in the final string.
103          *
104          * Since data will be parsed statically during a build step, some restrictions
105          * are applied with respect to how minErr instances are created and called.
106          * Instances should have names of the form namespaceMinErr for a minErr created
107          * using minErr('namespace') . Error codes, namespaces and template strings
108          * should all be static strings, not variables or general expressions.
109          *
110          * @param {string} module The namespace to use for the new minErr instance.
111          * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
112          *   error from returned function, for cases when a particular type of error is useful.
113          * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
114          */
115
116         function minErr(module, ErrorConstructor) {
117           ErrorConstructor = ErrorConstructor || Error;
118           return function() {
119             var SKIP_INDEXES = 2;
120
121             var templateArgs = arguments,
122               code = templateArgs[0],
123               message = '[' + (module ? module + ':' : '') + code + '] ',
124               template = templateArgs[1],
125               paramPrefix, i;
126
127             message += template.replace(/\{\d+\}/g, function(match) {
128               var index = +match.slice(1, -1),
129                 shiftedIndex = index + SKIP_INDEXES;
130
131               if (shiftedIndex < templateArgs.length) {
132                 return toDebugString(templateArgs[shiftedIndex]);
133               }
134
135               return match;
136             });
137
138             message += '\nhttp://errors.angularjs.org/1.4.8/' +
139               (module ? module + '/' : '') + code;
140
141             for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
142               message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
143                 encodeURIComponent(toDebugString(templateArgs[i]));
144             }
145
146             return new ErrorConstructor(message);
147           };
148         }
149
150         /* We need to tell jshint what variables are being exported */
151         /* global angular: true,
152           msie: true,
153           jqLite: true,
154           jQuery: true,
155           slice: true,
156           splice: true,
157           push: true,
158           toString: true,
159           ngMinErr: true,
160           angularModule: true,
161           uid: true,
162           REGEX_STRING_REGEXP: true,
163           VALIDITY_STATE_PROPERTY: true,
164
165           lowercase: true,
166           uppercase: true,
167           manualLowercase: true,
168           manualUppercase: true,
169           nodeName_: true,
170           isArrayLike: true,
171           forEach: true,
172           forEachSorted: true,
173           reverseParams: true,
174           nextUid: true,
175           setHashKey: true,
176           extend: true,
177           toInt: true,
178           inherit: true,
179           merge: true,
180           noop: true,
181           identity: true,
182           valueFn: true,
183           isUndefined: true,
184           isDefined: true,
185           isObject: true,
186           isBlankObject: true,
187           isString: true,
188           isNumber: true,
189           isDate: true,
190           isArray: true,
191           isFunction: true,
192           isRegExp: true,
193           isWindow: true,
194           isScope: true,
195           isFile: true,
196           isFormData: true,
197           isBlob: true,
198           isBoolean: true,
199           isPromiseLike: true,
200           trim: true,
201           escapeForRegexp: true,
202           isElement: true,
203           makeMap: true,
204           includes: true,
205           arrayRemove: true,
206           copy: true,
207           shallowCopy: true,
208           equals: true,
209           csp: true,
210           jq: true,
211           concat: true,
212           sliceArgs: true,
213           bind: true,
214           toJsonReplacer: true,
215           toJson: true,
216           fromJson: true,
217           convertTimezoneToLocal: true,
218           timezoneToOffset: true,
219           startingTag: true,
220           tryDecodeURIComponent: true,
221           parseKeyValue: true,
222           toKeyValue: true,
223           encodeUriSegment: true,
224           encodeUriQuery: true,
225           angularInit: true,
226           bootstrap: true,
227           getTestability: true,
228           snake_case: true,
229           bindJQuery: true,
230           assertArg: true,
231           assertArgFn: true,
232           assertNotHasOwnProperty: true,
233           getter: true,
234           getBlockNodes: true,
235           hasOwnProperty: true,
236           createMap: true,
237
238           NODE_TYPE_ELEMENT: true,
239           NODE_TYPE_ATTRIBUTE: true,
240           NODE_TYPE_TEXT: true,
241           NODE_TYPE_COMMENT: true,
242           NODE_TYPE_DOCUMENT: true,
243           NODE_TYPE_DOCUMENT_FRAGMENT: true,
244         */
245
246         ////////////////////////////////////
247
248         /**
249          * @ngdoc module
250          * @name ng
251          * @module ng
252          * @description
253          *
254          * # ng (core module)
255          * The ng module is loaded by default when an AngularJS application is started. The module itself
256          * contains the essential components for an AngularJS application to function. The table below
257          * lists a high level breakdown of each of the services/factories, filters, directives and testing
258          * components available within this core module.
259          *
260          * <div doc-module-components="ng"></div>
261          */
262
263         var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
264
265         // The name of a form control's ValidityState property.
266         // This is used so that it's possible for internal tests to create mock ValidityStates.
267         var VALIDITY_STATE_PROPERTY = 'validity';
268
269         /**
270          * @ngdoc function
271          * @name angular.lowercase
272          * @module ng
273          * @kind function
274          *
275          * @description Converts the specified string to lowercase.
276          * @param {string} string String to be converted to lowercase.
277          * @returns {string} Lowercased string.
278          */
279         var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
280         var hasOwnProperty = Object.prototype.hasOwnProperty;
281
282         /**
283          * @ngdoc function
284          * @name angular.uppercase
285          * @module ng
286          * @kind function
287          *
288          * @description Converts the specified string to uppercase.
289          * @param {string} string String to be converted to uppercase.
290          * @returns {string} Uppercased string.
291          */
292         var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
293
294
295         var manualLowercase = function(s) {
296           /* jshint bitwise: false */
297           return isString(s)
298               ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
299               : s;
300         };
301         var manualUppercase = function(s) {
302           /* jshint bitwise: false */
303           return isString(s)
304               ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
305               : s;
306         };
307
308
309         // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
310         // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
311         // with correct but slower alternatives.
312         if ('i' !== 'I'.toLowerCase()) {
313           lowercase = manualLowercase;
314           uppercase = manualUppercase;
315         }
316
317
318         var
319             msie,             // holds major version number for IE, or NaN if UA is not IE.
320             jqLite,           // delay binding since jQuery could be loaded after us.
321             jQuery,           // delay binding
322             slice             = [].slice,
323             splice            = [].splice,
324             push              = [].push,
325             toString          = Object.prototype.toString,
326             getPrototypeOf    = Object.getPrototypeOf,
327             ngMinErr          = minErr('ng'),
328
329             /** @name angular */
330             angular           = window.angular || (window.angular = {}),
331             angularModule,
332             uid               = 0;
333
334         /**
335          * documentMode is an IE-only property
336          * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
337          */
338         msie = document.documentMode;
339
340
341         /**
342          * @private
343          * @param {*} obj
344          * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
345          *                   String ...)
346          */
347         function isArrayLike(obj) {
348
349           // `null`, `undefined` and `window` are not array-like
350           if (obj == null || isWindow(obj)) return false;
351
352           // arrays, strings and jQuery/jqLite objects are array like
353           // * jqLite is either the jQuery or jqLite constructor function
354           // * we have to check the existance of jqLite first as this method is called
355           //   via the forEach method when constructing the jqLite object in the first place
356           if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
357
358           // Support: iOS 8.2 (not reproducible in simulator)
359           // "length" in obj used to prevent JIT error (gh-11508)
360           var length = "length" in Object(obj) && obj.length;
361
362           // NodeList objects (with `item` method) and
363           // other objects with suitable length characteristics are array-like
364           return isNumber(length) &&
365             (length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
366         }
367
368         /**
369          * @ngdoc function
370          * @name angular.forEach
371          * @module ng
372          * @kind function
373          *
374          * @description
375          * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
376          * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
377          * is the value of an object property or an array element, `key` is the object property key or
378          * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
379          *
380          * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
381          * using the `hasOwnProperty` method.
382          *
383          * Unlike ES262's
384          * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
385          * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
386          * return the value provided.
387          *
388            ```js
389              var values = {name: 'misko', gender: 'male'};
390              var log = [];
391              angular.forEach(values, function(value, key) {
392                this.push(key + ': ' + value);
393              }, log);
394              expect(log).toEqual(['name: misko', 'gender: male']);
395            ```
396          *
397          * @param {Object|Array} obj Object to iterate over.
398          * @param {Function} iterator Iterator function.
399          * @param {Object=} context Object to become context (`this`) for the iterator function.
400          * @returns {Object|Array} Reference to `obj`.
401          */
402
403         function forEach(obj, iterator, context) {
404           var key, length;
405           if (obj) {
406             if (isFunction(obj)) {
407               for (key in obj) {
408                 // Need to check if hasOwnProperty exists,
409                 // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
410                 if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
411                   iterator.call(context, obj[key], key, obj);
412                 }
413               }
414             } else if (isArray(obj) || isArrayLike(obj)) {
415               var isPrimitive = typeof obj !== 'object';
416               for (key = 0, length = obj.length; key < length; key++) {
417                 if (isPrimitive || key in obj) {
418                   iterator.call(context, obj[key], key, obj);
419                 }
420               }
421             } else if (obj.forEach && obj.forEach !== forEach) {
422                 obj.forEach(iterator, context, obj);
423             } else if (isBlankObject(obj)) {
424               // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
425               for (key in obj) {
426                 iterator.call(context, obj[key], key, obj);
427               }
428             } else if (typeof obj.hasOwnProperty === 'function') {
429               // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
430               for (key in obj) {
431                 if (obj.hasOwnProperty(key)) {
432                   iterator.call(context, obj[key], key, obj);
433                 }
434               }
435             } else {
436               // Slow path for objects which do not have a method `hasOwnProperty`
437               for (key in obj) {
438                 if (hasOwnProperty.call(obj, key)) {
439                   iterator.call(context, obj[key], key, obj);
440                 }
441               }
442             }
443           }
444           return obj;
445         }
446
447         function forEachSorted(obj, iterator, context) {
448           var keys = Object.keys(obj).sort();
449           for (var i = 0; i < keys.length; i++) {
450             iterator.call(context, obj[keys[i]], keys[i]);
451           }
452           return keys;
453         }
454
455
456         /**
457          * when using forEach the params are value, key, but it is often useful to have key, value.
458          * @param {function(string, *)} iteratorFn
459          * @returns {function(*, string)}
460          */
461         function reverseParams(iteratorFn) {
462           return function(value, key) { iteratorFn(key, value); };
463         }
464
465         /**
466          * A consistent way of creating unique IDs in angular.
467          *
468          * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
469          * we hit number precision issues in JavaScript.
470          *
471          * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
472          *
473          * @returns {number} an unique alpha-numeric string
474          */
475         function nextUid() {
476           return ++uid;
477         }
478
479
480         /**
481          * Set or clear the hashkey for an object.
482          * @param obj object
483          * @param h the hashkey (!truthy to delete the hashkey)
484          */
485         function setHashKey(obj, h) {
486           if (h) {
487             obj.$$hashKey = h;
488           } else {
489             delete obj.$$hashKey;
490           }
491         }
492
493
494         function baseExtend(dst, objs, deep) {
495           var h = dst.$$hashKey;
496
497           for (var i = 0, ii = objs.length; i < ii; ++i) {
498             var obj = objs[i];
499             if (!isObject(obj) && !isFunction(obj)) continue;
500             var keys = Object.keys(obj);
501             for (var j = 0, jj = keys.length; j < jj; j++) {
502               var key = keys[j];
503               var src = obj[key];
504
505               if (deep && isObject(src)) {
506                 if (isDate(src)) {
507                   dst[key] = new Date(src.valueOf());
508                 } else if (isRegExp(src)) {
509                   dst[key] = new RegExp(src);
510                 } else if (src.nodeName) {
511                   dst[key] = src.cloneNode(true);
512                 } else if (isElement(src)) {
513                   dst[key] = src.clone();
514                 } else {
515                   if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
516                   baseExtend(dst[key], [src], true);
517                 }
518               } else {
519                 dst[key] = src;
520               }
521             }
522           }
523
524           setHashKey(dst, h);
525           return dst;
526         }
527
528         /**
529          * @ngdoc function
530          * @name angular.extend
531          * @module ng
532          * @kind function
533          *
534          * @description
535          * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
536          * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
537          * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
538          *
539          * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
540          * {@link angular.merge} for this.
541          *
542          * @param {Object} dst Destination object.
543          * @param {...Object} src Source object(s).
544          * @returns {Object} Reference to `dst`.
545          */
546         function extend(dst) {
547           return baseExtend(dst, slice.call(arguments, 1), false);
548         }
549
550
551         /**
552         * @ngdoc function
553         * @name angular.merge
554         * @module ng
555         * @kind function
556         *
557         * @description
558         * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
559         * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
560         * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
561         *
562         * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
563         * objects, performing a deep copy.
564         *
565         * @param {Object} dst Destination object.
566         * @param {...Object} src Source object(s).
567         * @returns {Object} Reference to `dst`.
568         */
569         function merge(dst) {
570           return baseExtend(dst, slice.call(arguments, 1), true);
571         }
572
573
574
575         function toInt(str) {
576           return parseInt(str, 10);
577         }
578
579
580         function inherit(parent, extra) {
581           return extend(Object.create(parent), extra);
582         }
583
584         /**
585          * @ngdoc function
586          * @name angular.noop
587          * @module ng
588          * @kind function
589          *
590          * @description
591          * A function that performs no operations. This function can be useful when writing code in the
592          * functional style.
593            ```js
594              function foo(callback) {
595                var result = calculateResult();
596                (callback || angular.noop)(result);
597              }
598            ```
599          */
600         function noop() {}
601         noop.$inject = [];
602
603
604         /**
605          * @ngdoc function
606          * @name angular.identity
607          * @module ng
608          * @kind function
609          *
610          * @description
611          * A function that returns its first argument. This function is useful when writing code in the
612          * functional style.
613          *
614            ```js
615              function transformer(transformationFn, value) {
616                return (transformationFn || angular.identity)(value);
617              };
618            ```
619           * @param {*} value to be returned.
620           * @returns {*} the value passed in.
621          */
622         function identity($) {return $;}
623         identity.$inject = [];
624
625
626         function valueFn(value) {return function() {return value;};}
627
628         function hasCustomToString(obj) {
629           return isFunction(obj.toString) && obj.toString !== toString;
630         }
631
632
633         /**
634          * @ngdoc function
635          * @name angular.isUndefined
636          * @module ng
637          * @kind function
638          *
639          * @description
640          * Determines if a reference is undefined.
641          *
642          * @param {*} value Reference to check.
643          * @returns {boolean} True if `value` is undefined.
644          */
645         function isUndefined(value) {return typeof value === 'undefined';}
646
647
648         /**
649          * @ngdoc function
650          * @name angular.isDefined
651          * @module ng
652          * @kind function
653          *
654          * @description
655          * Determines if a reference is defined.
656          *
657          * @param {*} value Reference to check.
658          * @returns {boolean} True if `value` is defined.
659          */
660         function isDefined(value) {return typeof value !== 'undefined';}
661
662
663         /**
664          * @ngdoc function
665          * @name angular.isObject
666          * @module ng
667          * @kind function
668          *
669          * @description
670          * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
671          * considered to be objects. Note that JavaScript arrays are objects.
672          *
673          * @param {*} value Reference to check.
674          * @returns {boolean} True if `value` is an `Object` but not `null`.
675          */
676         function isObject(value) {
677           // http://jsperf.com/isobject4
678           return value !== null && typeof value === 'object';
679         }
680
681
682         /**
683          * Determine if a value is an object with a null prototype
684          *
685          * @returns {boolean} True if `value` is an `Object` with a null prototype
686          */
687         function isBlankObject(value) {
688           return value !== null && typeof value === 'object' && !getPrototypeOf(value);
689         }
690
691
692         /**
693          * @ngdoc function
694          * @name angular.isString
695          * @module ng
696          * @kind function
697          *
698          * @description
699          * Determines if a reference is a `String`.
700          *
701          * @param {*} value Reference to check.
702          * @returns {boolean} True if `value` is a `String`.
703          */
704         function isString(value) {return typeof value === 'string';}
705
706
707         /**
708          * @ngdoc function
709          * @name angular.isNumber
710          * @module ng
711          * @kind function
712          *
713          * @description
714          * Determines if a reference is a `Number`.
715          *
716          * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
717          *
718          * If you wish to exclude these then you can use the native
719          * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
720          * method.
721          *
722          * @param {*} value Reference to check.
723          * @returns {boolean} True if `value` is a `Number`.
724          */
725         function isNumber(value) {return typeof value === 'number';}
726
727
728         /**
729          * @ngdoc function
730          * @name angular.isDate
731          * @module ng
732          * @kind function
733          *
734          * @description
735          * Determines if a value is a date.
736          *
737          * @param {*} value Reference to check.
738          * @returns {boolean} True if `value` is a `Date`.
739          */
740         function isDate(value) {
741           return toString.call(value) === '[object Date]';
742         }
743
744
745         /**
746          * @ngdoc function
747          * @name angular.isArray
748          * @module ng
749          * @kind function
750          *
751          * @description
752          * Determines if a reference is an `Array`.
753          *
754          * @param {*} value Reference to check.
755          * @returns {boolean} True if `value` is an `Array`.
756          */
757         var isArray = Array.isArray;
758
759         /**
760          * @ngdoc function
761          * @name angular.isFunction
762          * @module ng
763          * @kind function
764          *
765          * @description
766          * Determines if a reference is a `Function`.
767          *
768          * @param {*} value Reference to check.
769          * @returns {boolean} True if `value` is a `Function`.
770          */
771         function isFunction(value) {return typeof value === 'function';}
772
773
774         /**
775          * Determines if a value is a regular expression object.
776          *
777          * @private
778          * @param {*} value Reference to check.
779          * @returns {boolean} True if `value` is a `RegExp`.
780          */
781         function isRegExp(value) {
782           return toString.call(value) === '[object RegExp]';
783         }
784
785
786         /**
787          * Checks if `obj` is a window object.
788          *
789          * @private
790          * @param {*} obj Object to check
791          * @returns {boolean} True if `obj` is a window obj.
792          */
793         function isWindow(obj) {
794           return obj && obj.window === obj;
795         }
796
797
798         function isScope(obj) {
799           return obj && obj.$evalAsync && obj.$watch;
800         }
801
802
803         function isFile(obj) {
804           return toString.call(obj) === '[object File]';
805         }
806
807
808         function isFormData(obj) {
809           return toString.call(obj) === '[object FormData]';
810         }
811
812
813         function isBlob(obj) {
814           return toString.call(obj) === '[object Blob]';
815         }
816
817
818         function isBoolean(value) {
819           return typeof value === 'boolean';
820         }
821
822
823         function isPromiseLike(obj) {
824           return obj && isFunction(obj.then);
825         }
826
827
828         var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
829         function isTypedArray(value) {
830           return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
831         }
832
833
834         var trim = function(value) {
835           return isString(value) ? value.trim() : value;
836         };
837
838         // Copied from:
839         // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
840         // Prereq: s is a string.
841         var escapeForRegexp = function(s) {
842           return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
843                    replace(/\x08/g, '\\x08');
844         };
845
846
847         /**
848          * @ngdoc function
849          * @name angular.isElement
850          * @module ng
851          * @kind function
852          *
853          * @description
854          * Determines if a reference is a DOM element (or wrapped jQuery element).
855          *
856          * @param {*} value Reference to check.
857          * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
858          */
859         function isElement(node) {
860           return !!(node &&
861             (node.nodeName  // we are a direct element
862             || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
863         }
864
865         /**
866          * @param str 'key1,key2,...'
867          * @returns {object} in the form of {key1:true, key2:true, ...}
868          */
869         function makeMap(str) {
870           var obj = {}, items = str.split(","), i;
871           for (i = 0; i < items.length; i++) {
872             obj[items[i]] = true;
873           }
874           return obj;
875         }
876
877
878         function nodeName_(element) {
879           return lowercase(element.nodeName || (element[0] && element[0].nodeName));
880         }
881
882         function includes(array, obj) {
883           return Array.prototype.indexOf.call(array, obj) != -1;
884         }
885
886         function arrayRemove(array, value) {
887           var index = array.indexOf(value);
888           if (index >= 0) {
889             array.splice(index, 1);
890           }
891           return index;
892         }
893
894         /**
895          * @ngdoc function
896          * @name angular.copy
897          * @module ng
898          * @kind function
899          *
900          * @description
901          * Creates a deep copy of `source`, which should be an object or an array.
902          *
903          * * If no destination is supplied, a copy of the object or array is created.
904          * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
905          *   are deleted and then all elements/properties from the source are copied to it.
906          * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
907          * * If `source` is identical to 'destination' an exception will be thrown.
908          *
909          * @param {*} source The source that will be used to make a copy.
910          *                   Can be any type, including primitives, `null`, and `undefined`.
911          * @param {(Object|Array)=} destination Destination into which the source is copied. If
912          *     provided, must be of the same type as `source`.
913          * @returns {*} The copy or updated `destination`, if `destination` was specified.
914          *
915          * @example
916          <example module="copyExample">
917          <file name="index.html">
918          <div ng-controller="ExampleController">
919          <form novalidate class="simple-form">
920          Name: <input type="text" ng-model="user.name" /><br />
921          E-mail: <input type="email" ng-model="user.email" /><br />
922          Gender: <input type="radio" ng-model="user.gender" value="male" />male
923          <input type="radio" ng-model="user.gender" value="female" />female<br />
924          <button ng-click="reset()">RESET</button>
925          <button ng-click="update(user)">SAVE</button>
926          </form>
927          <pre>form = {{user | json}}</pre>
928          <pre>master = {{master | json}}</pre>
929          </div>
930
931          <script>
932           angular.module('copyExample', [])
933             .controller('ExampleController', ['$scope', function($scope) {
934               $scope.master= {};
935
936               $scope.update = function(user) {
937                 // Example with 1 argument
938                 $scope.master= angular.copy(user);
939               };
940
941               $scope.reset = function() {
942                 // Example with 2 arguments
943                 angular.copy($scope.master, $scope.user);
944               };
945
946               $scope.reset();
947             }]);
948          </script>
949          </file>
950          </example>
951          */
952         function copy(source, destination) {
953           var stackSource = [];
954           var stackDest = [];
955
956           if (destination) {
957             if (isTypedArray(destination)) {
958               throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
959             }
960             if (source === destination) {
961               throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
962             }
963
964             // Empty the destination object
965             if (isArray(destination)) {
966               destination.length = 0;
967             } else {
968               forEach(destination, function(value, key) {
969                 if (key !== '$$hashKey') {
970                   delete destination[key];
971                 }
972               });
973             }
974
975             stackSource.push(source);
976             stackDest.push(destination);
977             return copyRecurse(source, destination);
978           }
979
980           return copyElement(source);
981
982           function copyRecurse(source, destination) {
983             var h = destination.$$hashKey;
984             var result, key;
985             if (isArray(source)) {
986               for (var i = 0, ii = source.length; i < ii; i++) {
987                 destination.push(copyElement(source[i]));
988               }
989             } else if (isBlankObject(source)) {
990               // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
991               for (key in source) {
992                 destination[key] = copyElement(source[key]);
993               }
994             } else if (source && typeof source.hasOwnProperty === 'function') {
995               // Slow path, which must rely on hasOwnProperty
996               for (key in source) {
997                 if (source.hasOwnProperty(key)) {
998                   destination[key] = copyElement(source[key]);
999                 }
1000               }
1001             } else {
1002               // Slowest path --- hasOwnProperty can't be called as a method
1003               for (key in source) {
1004                 if (hasOwnProperty.call(source, key)) {
1005                   destination[key] = copyElement(source[key]);
1006                 }
1007               }
1008             }
1009             setHashKey(destination, h);
1010             return destination;
1011           }
1012
1013           function copyElement(source) {
1014             // Simple values
1015             if (!isObject(source)) {
1016               return source;
1017             }
1018
1019             // Already copied values
1020             var index = stackSource.indexOf(source);
1021             if (index !== -1) {
1022               return stackDest[index];
1023             }
1024
1025             if (isWindow(source) || isScope(source)) {
1026               throw ngMinErr('cpws',
1027                 "Can't copy! Making copies of Window or Scope instances is not supported.");
1028             }
1029
1030             var needsRecurse = false;
1031             var destination;
1032
1033             if (isArray(source)) {
1034               destination = [];
1035               needsRecurse = true;
1036             } else if (isTypedArray(source)) {
1037               destination = new source.constructor(source);
1038             } else if (isDate(source)) {
1039               destination = new Date(source.getTime());
1040             } else if (isRegExp(source)) {
1041               destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
1042               destination.lastIndex = source.lastIndex;
1043             } else if (isFunction(source.cloneNode)) {
1044                 destination = source.cloneNode(true);
1045             } else {
1046               destination = Object.create(getPrototypeOf(source));
1047               needsRecurse = true;
1048             }
1049
1050             stackSource.push(source);
1051             stackDest.push(destination);
1052
1053             return needsRecurse
1054               ? copyRecurse(source, destination)
1055               : destination;
1056           }
1057         }
1058
1059         /**
1060          * Creates a shallow copy of an object, an array or a primitive.
1061          *
1062          * Assumes that there are no proto properties for objects.
1063          */
1064         function shallowCopy(src, dst) {
1065           if (isArray(src)) {
1066             dst = dst || [];
1067
1068             for (var i = 0, ii = src.length; i < ii; i++) {
1069               dst[i] = src[i];
1070             }
1071           } else if (isObject(src)) {
1072             dst = dst || {};
1073
1074             for (var key in src) {
1075               if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
1076                 dst[key] = src[key];
1077               }
1078             }
1079           }
1080
1081           return dst || src;
1082         }
1083
1084
1085         /**
1086          * @ngdoc function
1087          * @name angular.equals
1088          * @module ng
1089          * @kind function
1090          *
1091          * @description
1092          * Determines if two objects or two values are equivalent. Supports value types, regular
1093          * expressions, arrays and objects.
1094          *
1095          * Two objects or values are considered equivalent if at least one of the following is true:
1096          *
1097          * * Both objects or values pass `===` comparison.
1098          * * Both objects or values are of the same type and all of their properties are equal by
1099          *   comparing them with `angular.equals`.
1100          * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
1101          * * Both values represent the same regular expression (In JavaScript,
1102          *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
1103          *   representation matches).
1104          *
1105          * During a property comparison, properties of `function` type and properties with names
1106          * that begin with `$` are ignored.
1107          *
1108          * Scope and DOMWindow objects are being compared only by identify (`===`).
1109          *
1110          * @param {*} o1 Object or value to compare.
1111          * @param {*} o2 Object or value to compare.
1112          * @returns {boolean} True if arguments are equal.
1113          */
1114         function equals(o1, o2) {
1115           if (o1 === o2) return true;
1116           if (o1 === null || o2 === null) return false;
1117           if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1118           var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1119           if (t1 == t2) {
1120             if (t1 == 'object') {
1121               if (isArray(o1)) {
1122                 if (!isArray(o2)) return false;
1123                 if ((length = o1.length) == o2.length) {
1124                   for (key = 0; key < length; key++) {
1125                     if (!equals(o1[key], o2[key])) return false;
1126                   }
1127                   return true;
1128                 }
1129               } else if (isDate(o1)) {
1130                 if (!isDate(o2)) return false;
1131                 return equals(o1.getTime(), o2.getTime());
1132               } else if (isRegExp(o1)) {
1133                 return isRegExp(o2) ? o1.toString() == o2.toString() : false;
1134               } else {
1135                 if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1136                   isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1137                 keySet = createMap();
1138                 for (key in o1) {
1139                   if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1140                   if (!equals(o1[key], o2[key])) return false;
1141                   keySet[key] = true;
1142                 }
1143                 for (key in o2) {
1144                   if (!(key in keySet) &&
1145                       key.charAt(0) !== '$' &&
1146                       isDefined(o2[key]) &&
1147                       !isFunction(o2[key])) return false;
1148                 }
1149                 return true;
1150               }
1151             }
1152           }
1153           return false;
1154         }
1155
1156         var csp = function() {
1157           if (!isDefined(csp.rules)) {
1158
1159
1160             var ngCspElement = (document.querySelector('[ng-csp]') ||
1161                             document.querySelector('[data-ng-csp]'));
1162
1163             if (ngCspElement) {
1164               var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
1165                             ngCspElement.getAttribute('data-ng-csp');
1166               csp.rules = {
1167                 noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
1168                 noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
1169               };
1170             } else {
1171               csp.rules = {
1172                 noUnsafeEval: noUnsafeEval(),
1173                 noInlineStyle: false
1174               };
1175             }
1176           }
1177
1178           return csp.rules;
1179
1180           function noUnsafeEval() {
1181             try {
1182               /* jshint -W031, -W054 */
1183               new Function('');
1184               /* jshint +W031, +W054 */
1185               return false;
1186             } catch (e) {
1187               return true;
1188             }
1189           }
1190         };
1191
1192         /**
1193          * @ngdoc directive
1194          * @module ng
1195          * @name ngJq
1196          *
1197          * @element ANY
1198          * @param {string=} ngJq the name of the library available under `window`
1199          * to be used for angular.element
1200          * @description
1201          * Use this directive to force the angular.element library.  This should be
1202          * used to force either jqLite by leaving ng-jq blank or setting the name of
1203          * the jquery variable under window (eg. jQuery).
1204          *
1205          * Since angular looks for this directive when it is loaded (doesn't wait for the
1206          * DOMContentLoaded event), it must be placed on an element that comes before the script
1207          * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1208          * others ignored.
1209          *
1210          * @example
1211          * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1212          ```html
1213          <!doctype html>
1214          <html ng-app ng-jq>
1215          ...
1216          ...
1217          </html>
1218          ```
1219          * @example
1220          * This example shows how to use a jQuery based library of a different name.
1221          * The library name must be available at the top most 'window'.
1222          ```html
1223          <!doctype html>
1224          <html ng-app ng-jq="jQueryLib">
1225          ...
1226          ...
1227          </html>
1228          ```
1229          */
1230         var jq = function() {
1231           if (isDefined(jq.name_)) return jq.name_;
1232           var el;
1233           var i, ii = ngAttrPrefixes.length, prefix, name;
1234           for (i = 0; i < ii; ++i) {
1235             prefix = ngAttrPrefixes[i];
1236             if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1237               name = el.getAttribute(prefix + 'jq');
1238               break;
1239             }
1240           }
1241
1242           return (jq.name_ = name);
1243         };
1244
1245         function concat(array1, array2, index) {
1246           return array1.concat(slice.call(array2, index));
1247         }
1248
1249         function sliceArgs(args, startIndex) {
1250           return slice.call(args, startIndex || 0);
1251         }
1252
1253
1254         /* jshint -W101 */
1255         /**
1256          * @ngdoc function
1257          * @name angular.bind
1258          * @module ng
1259          * @kind function
1260          *
1261          * @description
1262          * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1263          * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1264          * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1265          * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1266          *
1267          * @param {Object} self Context which `fn` should be evaluated in.
1268          * @param {function()} fn Function to be bound.
1269          * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1270          * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1271          */
1272         /* jshint +W101 */
1273         function bind(self, fn) {
1274           var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1275           if (isFunction(fn) && !(fn instanceof RegExp)) {
1276             return curryArgs.length
1277               ? function() {
1278                   return arguments.length
1279                     ? fn.apply(self, concat(curryArgs, arguments, 0))
1280                     : fn.apply(self, curryArgs);
1281                 }
1282               : function() {
1283                   return arguments.length
1284                     ? fn.apply(self, arguments)
1285                     : fn.call(self);
1286                 };
1287           } else {
1288             // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1289             return fn;
1290           }
1291         }
1292
1293
1294         function toJsonReplacer(key, value) {
1295           var val = value;
1296
1297           if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1298             val = undefined;
1299           } else if (isWindow(value)) {
1300             val = '$WINDOW';
1301           } else if (value &&  document === value) {
1302             val = '$DOCUMENT';
1303           } else if (isScope(value)) {
1304             val = '$SCOPE';
1305           }
1306
1307           return val;
1308         }
1309
1310
1311         /**
1312          * @ngdoc function
1313          * @name angular.toJson
1314          * @module ng
1315          * @kind function
1316          *
1317          * @description
1318          * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1319          * stripped since angular uses this notation internally.
1320          *
1321          * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1322          * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1323          *    If set to an integer, the JSON output will contain that many spaces per indentation.
1324          * @returns {string|undefined} JSON-ified string representing `obj`.
1325          */
1326         function toJson(obj, pretty) {
1327           if (typeof obj === 'undefined') return undefined;
1328           if (!isNumber(pretty)) {
1329             pretty = pretty ? 2 : null;
1330           }
1331           return JSON.stringify(obj, toJsonReplacer, pretty);
1332         }
1333
1334
1335         /**
1336          * @ngdoc function
1337          * @name angular.fromJson
1338          * @module ng
1339          * @kind function
1340          *
1341          * @description
1342          * Deserializes a JSON string.
1343          *
1344          * @param {string} json JSON string to deserialize.
1345          * @returns {Object|Array|string|number} Deserialized JSON string.
1346          */
1347         function fromJson(json) {
1348           return isString(json)
1349               ? JSON.parse(json)
1350               : json;
1351         }
1352
1353
1354         function timezoneToOffset(timezone, fallback) {
1355           var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1356           return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1357         }
1358
1359
1360         function addDateMinutes(date, minutes) {
1361           date = new Date(date.getTime());
1362           date.setMinutes(date.getMinutes() + minutes);
1363           return date;
1364         }
1365
1366
1367         function convertTimezoneToLocal(date, timezone, reverse) {
1368           reverse = reverse ? -1 : 1;
1369           var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
1370           return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
1371         }
1372
1373
1374         /**
1375          * @returns {string} Returns the string representation of the element.
1376          */
1377         function startingTag(element) {
1378           element = jqLite(element).clone();
1379           try {
1380             // turns out IE does not let you set .html() on elements which
1381             // are not allowed to have children. So we just ignore it.
1382             element.empty();
1383           } catch (e) {}
1384           var elemHtml = jqLite('<div>').append(element).html();
1385           try {
1386             return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1387                 elemHtml.
1388                   match(/^(<[^>]+>)/)[1].
1389                   replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1390           } catch (e) {
1391             return lowercase(elemHtml);
1392           }
1393
1394         }
1395
1396
1397         /////////////////////////////////////////////////
1398
1399         /**
1400          * Tries to decode the URI component without throwing an exception.
1401          *
1402          * @private
1403          * @param str value potential URI component to check.
1404          * @returns {boolean} True if `value` can be decoded
1405          * with the decodeURIComponent function.
1406          */
1407         function tryDecodeURIComponent(value) {
1408           try {
1409             return decodeURIComponent(value);
1410           } catch (e) {
1411             // Ignore any invalid uri component
1412           }
1413         }
1414
1415
1416         /**
1417          * Parses an escaped url query string into key-value pairs.
1418          * @returns {Object.<string,boolean|Array>}
1419          */
1420         function parseKeyValue(/**string*/keyValue) {
1421           var obj = {};
1422           forEach((keyValue || "").split('&'), function(keyValue) {
1423             var splitPoint, key, val;
1424             if (keyValue) {
1425               key = keyValue = keyValue.replace(/\+/g,'%20');
1426               splitPoint = keyValue.indexOf('=');
1427               if (splitPoint !== -1) {
1428                 key = keyValue.substring(0, splitPoint);
1429                 val = keyValue.substring(splitPoint + 1);
1430               }
1431               key = tryDecodeURIComponent(key);
1432               if (isDefined(key)) {
1433                 val = isDefined(val) ? tryDecodeURIComponent(val) : true;
1434                 if (!hasOwnProperty.call(obj, key)) {
1435                   obj[key] = val;
1436                 } else if (isArray(obj[key])) {
1437                   obj[key].push(val);
1438                 } else {
1439                   obj[key] = [obj[key],val];
1440                 }
1441               }
1442             }
1443           });
1444           return obj;
1445         }
1446
1447         function toKeyValue(obj) {
1448           var parts = [];
1449           forEach(obj, function(value, key) {
1450             if (isArray(value)) {
1451               forEach(value, function(arrayValue) {
1452                 parts.push(encodeUriQuery(key, true) +
1453                            (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1454               });
1455             } else {
1456             parts.push(encodeUriQuery(key, true) +
1457                        (value === true ? '' : '=' + encodeUriQuery(value, true)));
1458             }
1459           });
1460           return parts.length ? parts.join('&') : '';
1461         }
1462
1463
1464         /**
1465          * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1466          * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1467          * segments:
1468          *    segment       = *pchar
1469          *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1470          *    pct-encoded   = "%" HEXDIG HEXDIG
1471          *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1472          *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1473          *                     / "*" / "+" / "," / ";" / "="
1474          */
1475         function encodeUriSegment(val) {
1476           return encodeUriQuery(val, true).
1477                      replace(/%26/gi, '&').
1478                      replace(/%3D/gi, '=').
1479                      replace(/%2B/gi, '+');
1480         }
1481
1482
1483         /**
1484          * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1485          * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1486          * encoded per http://tools.ietf.org/html/rfc3986:
1487          *    query       = *( pchar / "/" / "?" )
1488          *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1489          *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1490          *    pct-encoded   = "%" HEXDIG HEXDIG
1491          *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1492          *                     / "*" / "+" / "," / ";" / "="
1493          */
1494         function encodeUriQuery(val, pctEncodeSpaces) {
1495           return encodeURIComponent(val).
1496                      replace(/%40/gi, '@').
1497                      replace(/%3A/gi, ':').
1498                      replace(/%24/g, '$').
1499                      replace(/%2C/gi, ',').
1500                      replace(/%3B/gi, ';').
1501                      replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1502         }
1503
1504         var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1505
1506         function getNgAttribute(element, ngAttr) {
1507           var attr, i, ii = ngAttrPrefixes.length;
1508           for (i = 0; i < ii; ++i) {
1509             attr = ngAttrPrefixes[i] + ngAttr;
1510             if (isString(attr = element.getAttribute(attr))) {
1511               return attr;
1512             }
1513           }
1514           return null;
1515         }
1516
1517         /**
1518          * @ngdoc directive
1519          * @name ngApp
1520          * @module ng
1521          *
1522          * @element ANY
1523          * @param {angular.Module} ngApp an optional application
1524          *   {@link angular.module module} name to load.
1525          * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1526          *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1527          *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1528          *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1529          *   tracking down the root of these bugs.
1530          *
1531          * @description
1532          *
1533          * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1534          * designates the **root element** of the application and is typically placed near the root element
1535          * of the page - e.g. on the `<body>` or `<html>` tags.
1536          *
1537          * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1538          * found in the document will be used to define the root element to auto-bootstrap as an
1539          * application. To run multiple applications in an HTML document you must manually bootstrap them using
1540          * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1541          *
1542          * You can specify an **AngularJS module** to be used as the root module for the application.  This
1543          * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1544          * should contain the application code needed or have dependencies on other modules that will
1545          * contain the code. See {@link angular.module} for more information.
1546          *
1547          * In the example below if the `ngApp` directive were not placed on the `html` element then the
1548          * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1549          * would not be resolved to `3`.
1550          *
1551          * `ngApp` is the easiest, and most common way to bootstrap an application.
1552          *
1553          <example module="ngAppDemo">
1554            <file name="index.html">
1555            <div ng-controller="ngAppDemoController">
1556              I can add: {{a}} + {{b}} =  {{ a+b }}
1557            </div>
1558            </file>
1559            <file name="script.js">
1560            angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1561              $scope.a = 1;
1562              $scope.b = 2;
1563            });
1564            </file>
1565          </example>
1566          *
1567          * Using `ngStrictDi`, you would see something like this:
1568          *
1569          <example ng-app-included="true">
1570            <file name="index.html">
1571            <div ng-app="ngAppStrictDemo" ng-strict-di>
1572                <div ng-controller="GoodController1">
1573                    I can add: {{a}} + {{b}} =  {{ a+b }}
1574
1575                    <p>This renders because the controller does not fail to
1576                       instantiate, by using explicit annotation style (see
1577                       script.js for details)
1578                    </p>
1579                </div>
1580
1581                <div ng-controller="GoodController2">
1582                    Name: <input ng-model="name"><br />
1583                    Hello, {{name}}!
1584
1585                    <p>This renders because the controller does not fail to
1586                       instantiate, by using explicit annotation style
1587                       (see script.js for details)
1588                    </p>
1589                </div>
1590
1591                <div ng-controller="BadController">
1592                    I can add: {{a}} + {{b}} =  {{ a+b }}
1593
1594                    <p>The controller could not be instantiated, due to relying
1595                       on automatic function annotations (which are disabled in
1596                       strict mode). As such, the content of this section is not
1597                       interpolated, and there should be an error in your web console.
1598                    </p>
1599                </div>
1600            </div>
1601            </file>
1602            <file name="script.js">
1603            angular.module('ngAppStrictDemo', [])
1604              // BadController will fail to instantiate, due to relying on automatic function annotation,
1605              // rather than an explicit annotation
1606              .controller('BadController', function($scope) {
1607                $scope.a = 1;
1608                $scope.b = 2;
1609              })
1610              // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1611              // due to using explicit annotations using the array style and $inject property, respectively.
1612              .controller('GoodController1', ['$scope', function($scope) {
1613                $scope.a = 1;
1614                $scope.b = 2;
1615              }])
1616              .controller('GoodController2', GoodController2);
1617              function GoodController2($scope) {
1618                $scope.name = "World";
1619              }
1620              GoodController2.$inject = ['$scope'];
1621            </file>
1622            <file name="style.css">
1623            div[ng-controller] {
1624                margin-bottom: 1em;
1625                -webkit-border-radius: 4px;
1626                border-radius: 4px;
1627                border: 1px solid;
1628                padding: .5em;
1629            }
1630            div[ng-controller^=Good] {
1631                border-color: #d6e9c6;
1632                background-color: #dff0d8;
1633                color: #3c763d;
1634            }
1635            div[ng-controller^=Bad] {
1636                border-color: #ebccd1;
1637                background-color: #f2dede;
1638                color: #a94442;
1639                margin-bottom: 0;
1640            }
1641            </file>
1642          </example>
1643          */
1644         function angularInit(element, bootstrap) {
1645           var appElement,
1646               module,
1647               config = {};
1648
1649           // The element `element` has priority over any other element
1650           forEach(ngAttrPrefixes, function(prefix) {
1651             var name = prefix + 'app';
1652
1653             if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1654               appElement = element;
1655               module = element.getAttribute(name);
1656             }
1657           });
1658           forEach(ngAttrPrefixes, function(prefix) {
1659             var name = prefix + 'app';
1660             var candidate;
1661
1662             if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1663               appElement = candidate;
1664               module = candidate.getAttribute(name);
1665             }
1666           });
1667           if (appElement) {
1668             config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1669             bootstrap(appElement, module ? [module] : [], config);
1670           }
1671         }
1672
1673         /**
1674          * @ngdoc function
1675          * @name angular.bootstrap
1676          * @module ng
1677          * @description
1678          * Use this function to manually start up angular application.
1679          *
1680          * See: {@link guide/bootstrap Bootstrap}
1681          *
1682          * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1683          * They must use {@link ng.directive:ngApp ngApp}.
1684          *
1685          * Angular will detect if it has been loaded into the browser more than once and only allow the
1686          * first loaded script to be bootstrapped and will report a warning to the browser console for
1687          * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1688          * multiple instances of Angular try to work on the DOM.
1689          *
1690          * ```html
1691          * <!doctype html>
1692          * <html>
1693          * <body>
1694          * <div ng-controller="WelcomeController">
1695          *   {{greeting}}
1696          * </div>
1697          *
1698          * <script src="angular.js"></script>
1699          * <script>
1700          *   var app = angular.module('demo', [])
1701          *   .controller('WelcomeController', function($scope) {
1702          *       $scope.greeting = 'Welcome!';
1703          *   });
1704          *   angular.bootstrap(document, ['demo']);
1705          * </script>
1706          * </body>
1707          * </html>
1708          * ```
1709          *
1710          * @param {DOMElement} element DOM element which is the root of angular application.
1711          * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1712          *     Each item in the array should be the name of a predefined module or a (DI annotated)
1713          *     function that will be invoked by the injector as a `config` block.
1714          *     See: {@link angular.module modules}
1715          * @param {Object=} config an object for defining configuration options for the application. The
1716          *     following keys are supported:
1717          *
1718          * * `strictDi` - disable automatic function annotation for the application. This is meant to
1719          *   assist in finding bugs which break minified code. Defaults to `false`.
1720          *
1721          * @returns {auto.$injector} Returns the newly created injector for this app.
1722          */
1723         function bootstrap(element, modules, config) {
1724           if (!isObject(config)) config = {};
1725           var defaultConfig = {
1726             strictDi: false
1727           };
1728           config = extend(defaultConfig, config);
1729           var doBootstrap = function() {
1730             element = jqLite(element);
1731
1732             if (element.injector()) {
1733               var tag = (element[0] === document) ? 'document' : startingTag(element);
1734               //Encode angle brackets to prevent input from being sanitized to empty string #8683
1735               throw ngMinErr(
1736                   'btstrpd',
1737                   "App Already Bootstrapped with this Element '{0}'",
1738                   tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1739             }
1740
1741             modules = modules || [];
1742             modules.unshift(['$provide', function($provide) {
1743               $provide.value('$rootElement', element);
1744             }]);
1745
1746             if (config.debugInfoEnabled) {
1747               // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1748               modules.push(['$compileProvider', function($compileProvider) {
1749                 $compileProvider.debugInfoEnabled(true);
1750               }]);
1751             }
1752
1753             modules.unshift('ng');
1754             var injector = createInjector(modules, config.strictDi);
1755             injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1756                function bootstrapApply(scope, element, compile, injector) {
1757                 scope.$apply(function() {
1758                   element.data('$injector', injector);
1759                   compile(element)(scope);
1760                 });
1761               }]
1762             );
1763             return injector;
1764           };
1765
1766           var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1767           var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1768
1769           if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1770             config.debugInfoEnabled = true;
1771             window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1772           }
1773
1774           if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1775             return doBootstrap();
1776           }
1777
1778           window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1779           angular.resumeBootstrap = function(extraModules) {
1780             forEach(extraModules, function(module) {
1781               modules.push(module);
1782             });
1783             return doBootstrap();
1784           };
1785
1786           if (isFunction(angular.resumeDeferredBootstrap)) {
1787             angular.resumeDeferredBootstrap();
1788           }
1789         }
1790
1791         /**
1792          * @ngdoc function
1793          * @name angular.reloadWithDebugInfo
1794          * @module ng
1795          * @description
1796          * Use this function to reload the current application with debug information turned on.
1797          * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1798          *
1799          * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1800          */
1801         function reloadWithDebugInfo() {
1802           window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1803           window.location.reload();
1804         }
1805
1806         /**
1807          * @name angular.getTestability
1808          * @module ng
1809          * @description
1810          * Get the testability service for the instance of Angular on the given
1811          * element.
1812          * @param {DOMElement} element DOM element which is the root of angular application.
1813          */
1814         function getTestability(rootElement) {
1815           var injector = angular.element(rootElement).injector();
1816           if (!injector) {
1817             throw ngMinErr('test',
1818               'no injector found for element argument to getTestability');
1819           }
1820           return injector.get('$$testability');
1821         }
1822
1823         var SNAKE_CASE_REGEXP = /[A-Z]/g;
1824         function snake_case(name, separator) {
1825           separator = separator || '_';
1826           return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1827             return (pos ? separator : '') + letter.toLowerCase();
1828           });
1829         }
1830
1831         var bindJQueryFired = false;
1832         var skipDestroyOnNextJQueryCleanData;
1833         function bindJQuery() {
1834           var originalCleanData;
1835
1836           if (bindJQueryFired) {
1837             return;
1838           }
1839
1840           // bind to jQuery if present;
1841           var jqName = jq();
1842           jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
1843                    !jqName             ? undefined     :   // use jqLite
1844                                          window[jqName];   // use jQuery specified by `ngJq`
1845
1846           // Use jQuery if it exists with proper functionality, otherwise default to us.
1847           // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1848           // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1849           // versions. It will not work for sure with jQuery <1.7, though.
1850           if (jQuery && jQuery.fn.on) {
1851             jqLite = jQuery;
1852             extend(jQuery.fn, {
1853               scope: JQLitePrototype.scope,
1854               isolateScope: JQLitePrototype.isolateScope,
1855               controller: JQLitePrototype.controller,
1856               injector: JQLitePrototype.injector,
1857               inheritedData: JQLitePrototype.inheritedData
1858             });
1859
1860             // All nodes removed from the DOM via various jQuery APIs like .remove()
1861             // are passed through jQuery.cleanData. Monkey-patch this method to fire
1862             // the $destroy event on all removed nodes.
1863             originalCleanData = jQuery.cleanData;
1864             jQuery.cleanData = function(elems) {
1865               var events;
1866               if (!skipDestroyOnNextJQueryCleanData) {
1867                 for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1868                   events = jQuery._data(elem, "events");
1869                   if (events && events.$destroy) {
1870                     jQuery(elem).triggerHandler('$destroy');
1871                   }
1872                 }
1873               } else {
1874                 skipDestroyOnNextJQueryCleanData = false;
1875               }
1876               originalCleanData(elems);
1877             };
1878           } else {
1879             jqLite = JQLite;
1880           }
1881
1882           angular.element = jqLite;
1883
1884           // Prevent double-proxying.
1885           bindJQueryFired = true;
1886         }
1887
1888         /**
1889          * throw error if the argument is falsy.
1890          */
1891         function assertArg(arg, name, reason) {
1892           if (!arg) {
1893             throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1894           }
1895           return arg;
1896         }
1897
1898         function assertArgFn(arg, name, acceptArrayAnnotation) {
1899           if (acceptArrayAnnotation && isArray(arg)) {
1900               arg = arg[arg.length - 1];
1901           }
1902
1903           assertArg(isFunction(arg), name, 'not a function, got ' +
1904               (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1905           return arg;
1906         }
1907
1908         /**
1909          * throw error if the name given is hasOwnProperty
1910          * @param  {String} name    the name to test
1911          * @param  {String} context the context in which the name is used, such as module or directive
1912          */
1913         function assertNotHasOwnProperty(name, context) {
1914           if (name === 'hasOwnProperty') {
1915             throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1916           }
1917         }
1918
1919         /**
1920          * Return the value accessible from the object by path. Any undefined traversals are ignored
1921          * @param {Object} obj starting object
1922          * @param {String} path path to traverse
1923          * @param {boolean} [bindFnToScope=true]
1924          * @returns {Object} value as accessible by path
1925          */
1926         //TODO(misko): this function needs to be removed
1927         function getter(obj, path, bindFnToScope) {
1928           if (!path) return obj;
1929           var keys = path.split('.');
1930           var key;
1931           var lastInstance = obj;
1932           var len = keys.length;
1933
1934           for (var i = 0; i < len; i++) {
1935             key = keys[i];
1936             if (obj) {
1937               obj = (lastInstance = obj)[key];
1938             }
1939           }
1940           if (!bindFnToScope && isFunction(obj)) {
1941             return bind(lastInstance, obj);
1942           }
1943           return obj;
1944         }
1945
1946         /**
1947          * Return the DOM siblings between the first and last node in the given array.
1948          * @param {Array} array like object
1949          * @returns {Array} the inputted object or a jqLite collection containing the nodes
1950          */
1951         function getBlockNodes(nodes) {
1952           // TODO(perf): update `nodes` instead of creating a new object?
1953           var node = nodes[0];
1954           var endNode = nodes[nodes.length - 1];
1955           var blockNodes;
1956
1957           for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
1958             if (blockNodes || nodes[i] !== node) {
1959               if (!blockNodes) {
1960                 blockNodes = jqLite(slice.call(nodes, 0, i));
1961               }
1962               blockNodes.push(node);
1963             }
1964           }
1965
1966           return blockNodes || nodes;
1967         }
1968
1969
1970         /**
1971          * Creates a new object without a prototype. This object is useful for lookup without having to
1972          * guard against prototypically inherited properties via hasOwnProperty.
1973          *
1974          * Related micro-benchmarks:
1975          * - http://jsperf.com/object-create2
1976          * - http://jsperf.com/proto-map-lookup/2
1977          * - http://jsperf.com/for-in-vs-object-keys2
1978          *
1979          * @returns {Object}
1980          */
1981         function createMap() {
1982           return Object.create(null);
1983         }
1984
1985         var NODE_TYPE_ELEMENT = 1;
1986         var NODE_TYPE_ATTRIBUTE = 2;
1987         var NODE_TYPE_TEXT = 3;
1988         var NODE_TYPE_COMMENT = 8;
1989         var NODE_TYPE_DOCUMENT = 9;
1990         var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1991
1992         /**
1993          * @ngdoc type
1994          * @name angular.Module
1995          * @module ng
1996          * @description
1997          *
1998          * Interface for configuring angular {@link angular.module modules}.
1999          */
2000
2001         function setupModuleLoader(window) {
2002
2003           var $injectorMinErr = minErr('$injector');
2004           var ngMinErr = minErr('ng');
2005
2006           function ensure(obj, name, factory) {
2007             return obj[name] || (obj[name] = factory());
2008           }
2009
2010           var angular = ensure(window, 'angular', Object);
2011
2012           // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
2013           angular.$$minErr = angular.$$minErr || minErr;
2014
2015           return ensure(angular, 'module', function() {
2016             /** @type {Object.<string, angular.Module>} */
2017             var modules = {};
2018
2019             /**
2020              * @ngdoc function
2021              * @name angular.module
2022              * @module ng
2023              * @description
2024              *
2025              * The `angular.module` is a global place for creating, registering and retrieving Angular
2026              * modules.
2027              * All modules (angular core or 3rd party) that should be available to an application must be
2028              * registered using this mechanism.
2029              *
2030              * Passing one argument retrieves an existing {@link angular.Module},
2031              * whereas passing more than one argument creates a new {@link angular.Module}
2032              *
2033              *
2034              * # Module
2035              *
2036              * A module is a collection of services, directives, controllers, filters, and configuration information.
2037              * `angular.module` is used to configure the {@link auto.$injector $injector}.
2038              *
2039              * ```js
2040              * // Create a new module
2041              * var myModule = angular.module('myModule', []);
2042              *
2043              * // register a new service
2044              * myModule.value('appName', 'MyCoolApp');
2045              *
2046              * // configure existing services inside initialization blocks.
2047              * myModule.config(['$locationProvider', function($locationProvider) {
2048              *   // Configure existing providers
2049              *   $locationProvider.hashPrefix('!');
2050              * }]);
2051              * ```
2052              *
2053              * Then you can create an injector and load your modules like this:
2054              *
2055              * ```js
2056              * var injector = angular.injector(['ng', 'myModule'])
2057              * ```
2058              *
2059              * However it's more likely that you'll just use
2060              * {@link ng.directive:ngApp ngApp} or
2061              * {@link angular.bootstrap} to simplify this process for you.
2062              *
2063              * @param {!string} name The name of the module to create or retrieve.
2064              * @param {!Array.<string>=} requires If specified then new module is being created. If
2065              *        unspecified then the module is being retrieved for further configuration.
2066              * @param {Function=} configFn Optional configuration function for the module. Same as
2067              *        {@link angular.Module#config Module#config()}.
2068              * @returns {module} new module with the {@link angular.Module} api.
2069              */
2070             return function module(name, requires, configFn) {
2071               var assertNotHasOwnProperty = function(name, context) {
2072                 if (name === 'hasOwnProperty') {
2073                   throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
2074                 }
2075               };
2076
2077               assertNotHasOwnProperty(name, 'module');
2078               if (requires && modules.hasOwnProperty(name)) {
2079                 modules[name] = null;
2080               }
2081               return ensure(modules, name, function() {
2082                 if (!requires) {
2083                   throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
2084                      "the module name or forgot to load it. If registering a module ensure that you " +
2085                      "specify the dependencies as the second argument.", name);
2086                 }
2087
2088                 /** @type {!Array.<Array.<*>>} */
2089                 var invokeQueue = [];
2090
2091                 /** @type {!Array.<Function>} */
2092                 var configBlocks = [];
2093
2094                 /** @type {!Array.<Function>} */
2095                 var runBlocks = [];
2096
2097                 var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
2098
2099                 /** @type {angular.Module} */
2100                 var moduleInstance = {
2101                   // Private state
2102                   _invokeQueue: invokeQueue,
2103                   _configBlocks: configBlocks,
2104                   _runBlocks: runBlocks,
2105
2106                   /**
2107                    * @ngdoc property
2108                    * @name angular.Module#requires
2109                    * @module ng
2110                    *
2111                    * @description
2112                    * Holds the list of modules which the injector will load before the current module is
2113                    * loaded.
2114                    */
2115                   requires: requires,
2116
2117                   /**
2118                    * @ngdoc property
2119                    * @name angular.Module#name
2120                    * @module ng
2121                    *
2122                    * @description
2123                    * Name of the module.
2124                    */
2125                   name: name,
2126
2127
2128                   /**
2129                    * @ngdoc method
2130                    * @name angular.Module#provider
2131                    * @module ng
2132                    * @param {string} name service name
2133                    * @param {Function} providerType Construction function for creating new instance of the
2134                    *                                service.
2135                    * @description
2136                    * See {@link auto.$provide#provider $provide.provider()}.
2137                    */
2138                   provider: invokeLaterAndSetModuleName('$provide', 'provider'),
2139
2140                   /**
2141                    * @ngdoc method
2142                    * @name angular.Module#factory
2143                    * @module ng
2144                    * @param {string} name service name
2145                    * @param {Function} providerFunction Function for creating new instance of the service.
2146                    * @description
2147                    * See {@link auto.$provide#factory $provide.factory()}.
2148                    */
2149                   factory: invokeLaterAndSetModuleName('$provide', 'factory'),
2150
2151                   /**
2152                    * @ngdoc method
2153                    * @name angular.Module#service
2154                    * @module ng
2155                    * @param {string} name service name
2156                    * @param {Function} constructor A constructor function that will be instantiated.
2157                    * @description
2158                    * See {@link auto.$provide#service $provide.service()}.
2159                    */
2160                   service: invokeLaterAndSetModuleName('$provide', 'service'),
2161
2162                   /**
2163                    * @ngdoc method
2164                    * @name angular.Module#value
2165                    * @module ng
2166                    * @param {string} name service name
2167                    * @param {*} object Service instance object.
2168                    * @description
2169                    * See {@link auto.$provide#value $provide.value()}.
2170                    */
2171                   value: invokeLater('$provide', 'value'),
2172
2173                   /**
2174                    * @ngdoc method
2175                    * @name angular.Module#constant
2176                    * @module ng
2177                    * @param {string} name constant name
2178                    * @param {*} object Constant value.
2179                    * @description
2180                    * Because the constants are fixed, they get applied before other provide methods.
2181                    * See {@link auto.$provide#constant $provide.constant()}.
2182                    */
2183                   constant: invokeLater('$provide', 'constant', 'unshift'),
2184
2185                    /**
2186                    * @ngdoc method
2187                    * @name angular.Module#decorator
2188                    * @module ng
2189                    * @param {string} The name of the service to decorate.
2190                    * @param {Function} This function will be invoked when the service needs to be
2191                    *                                    instantiated and should return the decorated service instance.
2192                    * @description
2193                    * See {@link auto.$provide#decorator $provide.decorator()}.
2194                    */
2195                   decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
2196
2197                   /**
2198                    * @ngdoc method
2199                    * @name angular.Module#animation
2200                    * @module ng
2201                    * @param {string} name animation name
2202                    * @param {Function} animationFactory Factory function for creating new instance of an
2203                    *                                    animation.
2204                    * @description
2205                    *
2206                    * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
2207                    *
2208                    *
2209                    * Defines an animation hook that can be later used with
2210                    * {@link $animate $animate} service and directives that use this service.
2211                    *
2212                    * ```js
2213                    * module.animation('.animation-name', function($inject1, $inject2) {
2214                    *   return {
2215                    *     eventName : function(element, done) {
2216                    *       //code to run the animation
2217                    *       //once complete, then run done()
2218                    *       return function cancellationFunction(element) {
2219                    *         //code to cancel the animation
2220                    *       }
2221                    *     }
2222                    *   }
2223                    * })
2224                    * ```
2225                    *
2226                    * See {@link ng.$animateProvider#register $animateProvider.register()} and
2227                    * {@link ngAnimate ngAnimate module} for more information.
2228                    */
2229                   animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
2230
2231                   /**
2232                    * @ngdoc method
2233                    * @name angular.Module#filter
2234                    * @module ng
2235                    * @param {string} name Filter name - this must be a valid angular expression identifier
2236                    * @param {Function} filterFactory Factory function for creating new instance of filter.
2237                    * @description
2238                    * See {@link ng.$filterProvider#register $filterProvider.register()}.
2239                    *
2240                    * <div class="alert alert-warning">
2241                    * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
2242                    * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
2243                    * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
2244                    * (`myapp_subsection_filterx`).
2245                    * </div>
2246                    */
2247                   filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
2248
2249                   /**
2250                    * @ngdoc method
2251                    * @name angular.Module#controller
2252                    * @module ng
2253                    * @param {string|Object} name Controller name, or an object map of controllers where the
2254                    *    keys are the names and the values are the constructors.
2255                    * @param {Function} constructor Controller constructor function.
2256                    * @description
2257                    * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
2258                    */
2259                   controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
2260
2261                   /**
2262                    * @ngdoc method
2263                    * @name angular.Module#directive
2264                    * @module ng
2265                    * @param {string|Object} name Directive name, or an object map of directives where the
2266                    *    keys are the names and the values are the factories.
2267                    * @param {Function} directiveFactory Factory function for creating new instance of
2268                    * directives.
2269                    * @description
2270                    * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
2271                    */
2272                   directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
2273
2274                   /**
2275                    * @ngdoc method
2276                    * @name angular.Module#config
2277                    * @module ng
2278                    * @param {Function} configFn Execute this function on module load. Useful for service
2279                    *    configuration.
2280                    * @description
2281                    * Use this method to register work which needs to be performed on module loading.
2282                    * For more about how to configure services, see
2283                    * {@link providers#provider-recipe Provider Recipe}.
2284                    */
2285                   config: config,
2286
2287                   /**
2288                    * @ngdoc method
2289                    * @name angular.Module#run
2290                    * @module ng
2291                    * @param {Function} initializationFn Execute this function after injector creation.
2292                    *    Useful for application initialization.
2293                    * @description
2294                    * Use this method to register work which should be performed when the injector is done
2295                    * loading all modules.
2296                    */
2297                   run: function(block) {
2298                     runBlocks.push(block);
2299                     return this;
2300                   }
2301                 };
2302
2303                 if (configFn) {
2304                   config(configFn);
2305                 }
2306
2307                 return moduleInstance;
2308
2309                 /**
2310                  * @param {string} provider
2311                  * @param {string} method
2312                  * @param {String=} insertMethod
2313                  * @returns {angular.Module}
2314                  */
2315                 function invokeLater(provider, method, insertMethod, queue) {
2316                   if (!queue) queue = invokeQueue;
2317                   return function() {
2318                     queue[insertMethod || 'push']([provider, method, arguments]);
2319                     return moduleInstance;
2320                   };
2321                 }
2322
2323                 /**
2324                  * @param {string} provider
2325                  * @param {string} method
2326                  * @returns {angular.Module}
2327                  */
2328                 function invokeLaterAndSetModuleName(provider, method) {
2329                   return function(recipeName, factoryFunction) {
2330                     if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
2331                     invokeQueue.push([provider, method, arguments]);
2332                     return moduleInstance;
2333                   };
2334                 }
2335               });
2336             };
2337           });
2338
2339         }
2340
2341         /* global: toDebugString: true */
2342
2343         function serializeObject(obj) {
2344           var seen = [];
2345
2346           return JSON.stringify(obj, function(key, val) {
2347             val = toJsonReplacer(key, val);
2348             if (isObject(val)) {
2349
2350               if (seen.indexOf(val) >= 0) return '...';
2351
2352               seen.push(val);
2353             }
2354             return val;
2355           });
2356         }
2357
2358         function toDebugString(obj) {
2359           if (typeof obj === 'function') {
2360             return obj.toString().replace(/ \{[\s\S]*$/, '');
2361           } else if (isUndefined(obj)) {
2362             return 'undefined';
2363           } else if (typeof obj !== 'string') {
2364             return serializeObject(obj);
2365           }
2366           return obj;
2367         }
2368
2369         /* global angularModule: true,
2370           version: true,
2371
2372           $CompileProvider,
2373
2374           htmlAnchorDirective,
2375           inputDirective,
2376           inputDirective,
2377           formDirective,
2378           scriptDirective,
2379           selectDirective,
2380           styleDirective,
2381           optionDirective,
2382           ngBindDirective,
2383           ngBindHtmlDirective,
2384           ngBindTemplateDirective,
2385           ngClassDirective,
2386           ngClassEvenDirective,
2387           ngClassOddDirective,
2388           ngCloakDirective,
2389           ngControllerDirective,
2390           ngFormDirective,
2391           ngHideDirective,
2392           ngIfDirective,
2393           ngIncludeDirective,
2394           ngIncludeFillContentDirective,
2395           ngInitDirective,
2396           ngNonBindableDirective,
2397           ngPluralizeDirective,
2398           ngRepeatDirective,
2399           ngShowDirective,
2400           ngStyleDirective,
2401           ngSwitchDirective,
2402           ngSwitchWhenDirective,
2403           ngSwitchDefaultDirective,
2404           ngOptionsDirective,
2405           ngTranscludeDirective,
2406           ngModelDirective,
2407           ngListDirective,
2408           ngChangeDirective,
2409           patternDirective,
2410           patternDirective,
2411           requiredDirective,
2412           requiredDirective,
2413           minlengthDirective,
2414           minlengthDirective,
2415           maxlengthDirective,
2416           maxlengthDirective,
2417           ngValueDirective,
2418           ngModelOptionsDirective,
2419           ngAttributeAliasDirectives,
2420           ngEventDirectives,
2421
2422           $AnchorScrollProvider,
2423           $AnimateProvider,
2424           $CoreAnimateCssProvider,
2425           $$CoreAnimateQueueProvider,
2426           $$CoreAnimateRunnerProvider,
2427           $BrowserProvider,
2428           $CacheFactoryProvider,
2429           $ControllerProvider,
2430           $DocumentProvider,
2431           $ExceptionHandlerProvider,
2432           $FilterProvider,
2433           $$ForceReflowProvider,
2434           $InterpolateProvider,
2435           $IntervalProvider,
2436           $$HashMapProvider,
2437           $HttpProvider,
2438           $HttpParamSerializerProvider,
2439           $HttpParamSerializerJQLikeProvider,
2440           $HttpBackendProvider,
2441           $xhrFactoryProvider,
2442           $LocationProvider,
2443           $LogProvider,
2444           $ParseProvider,
2445           $RootScopeProvider,
2446           $QProvider,
2447           $$QProvider,
2448           $$SanitizeUriProvider,
2449           $SceProvider,
2450           $SceDelegateProvider,
2451           $SnifferProvider,
2452           $TemplateCacheProvider,
2453           $TemplateRequestProvider,
2454           $$TestabilityProvider,
2455           $TimeoutProvider,
2456           $$RAFProvider,
2457           $WindowProvider,
2458           $$jqLiteProvider,
2459           $$CookieReaderProvider
2460         */
2461
2462
2463         /**
2464          * @ngdoc object
2465          * @name angular.version
2466          * @module ng
2467          * @description
2468          * An object that contains information about the current AngularJS version.
2469          *
2470          * This object has the following properties:
2471          *
2472          * - `full` – `{string}` – Full version string, such as "0.9.18".
2473          * - `major` – `{number}` – Major version number, such as "0".
2474          * - `minor` – `{number}` – Minor version number, such as "9".
2475          * - `dot` – `{number}` – Dot version number, such as "18".
2476          * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2477          */
2478         var version = {
2479           full: '1.4.8',    // all of these placeholder strings will be replaced by grunt's
2480           major: 1,    // package task
2481           minor: 4,
2482           dot: 8,
2483           codeName: 'ice-manipulation'
2484         };
2485
2486
2487         function publishExternalAPI(angular) {
2488           extend(angular, {
2489             'bootstrap': bootstrap,
2490             'copy': copy,
2491             'extend': extend,
2492             'merge': merge,
2493             'equals': equals,
2494             'element': jqLite,
2495             'forEach': forEach,
2496             'injector': createInjector,
2497             'noop': noop,
2498             'bind': bind,
2499             'toJson': toJson,
2500             'fromJson': fromJson,
2501             'identity': identity,
2502             'isUndefined': isUndefined,
2503             'isDefined': isDefined,
2504             'isString': isString,
2505             'isFunction': isFunction,
2506             'isObject': isObject,
2507             'isNumber': isNumber,
2508             'isElement': isElement,
2509             'isArray': isArray,
2510             'version': version,
2511             'isDate': isDate,
2512             'lowercase': lowercase,
2513             'uppercase': uppercase,
2514             'callbacks': {counter: 0},
2515             'getTestability': getTestability,
2516             '$$minErr': minErr,
2517             '$$csp': csp,
2518             'reloadWithDebugInfo': reloadWithDebugInfo
2519           });
2520
2521           angularModule = setupModuleLoader(window);
2522
2523           angularModule('ng', ['ngLocale'], ['$provide',
2524             function ngModule($provide) {
2525               // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2526               $provide.provider({
2527                 $$sanitizeUri: $$SanitizeUriProvider
2528               });
2529               $provide.provider('$compile', $CompileProvider).
2530                 directive({
2531                     a: htmlAnchorDirective,
2532                     input: inputDirective,
2533                     textarea: inputDirective,
2534                     form: formDirective,
2535                     script: scriptDirective,
2536                     select: selectDirective,
2537                     style: styleDirective,
2538                     option: optionDirective,
2539                     ngBind: ngBindDirective,
2540                     ngBindHtml: ngBindHtmlDirective,
2541                     ngBindTemplate: ngBindTemplateDirective,
2542                     ngClass: ngClassDirective,
2543                     ngClassEven: ngClassEvenDirective,
2544                     ngClassOdd: ngClassOddDirective,
2545                     ngCloak: ngCloakDirective,
2546                     ngController: ngControllerDirective,
2547                     ngForm: ngFormDirective,
2548                     ngHide: ngHideDirective,
2549                     ngIf: ngIfDirective,
2550                     ngInclude: ngIncludeDirective,
2551                     ngInit: ngInitDirective,
2552                     ngNonBindable: ngNonBindableDirective,
2553                     ngPluralize: ngPluralizeDirective,
2554                     ngRepeat: ngRepeatDirective,
2555                     ngShow: ngShowDirective,
2556                     ngStyle: ngStyleDirective,
2557                     ngSwitch: ngSwitchDirective,
2558                     ngSwitchWhen: ngSwitchWhenDirective,
2559                     ngSwitchDefault: ngSwitchDefaultDirective,
2560                     ngOptions: ngOptionsDirective,
2561                     ngTransclude: ngTranscludeDirective,
2562                     ngModel: ngModelDirective,
2563                     ngList: ngListDirective,
2564                     ngChange: ngChangeDirective,
2565                     pattern: patternDirective,
2566                     ngPattern: patternDirective,
2567                     required: requiredDirective,
2568                     ngRequired: requiredDirective,
2569                     minlength: minlengthDirective,
2570                     ngMinlength: minlengthDirective,
2571                     maxlength: maxlengthDirective,
2572                     ngMaxlength: maxlengthDirective,
2573                     ngValue: ngValueDirective,
2574                     ngModelOptions: ngModelOptionsDirective
2575                 }).
2576                 directive({
2577                   ngInclude: ngIncludeFillContentDirective
2578                 }).
2579                 directive(ngAttributeAliasDirectives).
2580                 directive(ngEventDirectives);
2581               $provide.provider({
2582                 $anchorScroll: $AnchorScrollProvider,
2583                 $animate: $AnimateProvider,
2584                 $animateCss: $CoreAnimateCssProvider,
2585                 $$animateQueue: $$CoreAnimateQueueProvider,
2586                 $$AnimateRunner: $$CoreAnimateRunnerProvider,
2587                 $browser: $BrowserProvider,
2588                 $cacheFactory: $CacheFactoryProvider,
2589                 $controller: $ControllerProvider,
2590                 $document: $DocumentProvider,
2591                 $exceptionHandler: $ExceptionHandlerProvider,
2592                 $filter: $FilterProvider,
2593                 $$forceReflow: $$ForceReflowProvider,
2594                 $interpolate: $InterpolateProvider,
2595                 $interval: $IntervalProvider,
2596                 $http: $HttpProvider,
2597                 $httpParamSerializer: $HttpParamSerializerProvider,
2598                 $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
2599                 $httpBackend: $HttpBackendProvider,
2600                 $xhrFactory: $xhrFactoryProvider,
2601                 $location: $LocationProvider,
2602                 $log: $LogProvider,
2603                 $parse: $ParseProvider,
2604                 $rootScope: $RootScopeProvider,
2605                 $q: $QProvider,
2606                 $$q: $$QProvider,
2607                 $sce: $SceProvider,
2608                 $sceDelegate: $SceDelegateProvider,
2609                 $sniffer: $SnifferProvider,
2610                 $templateCache: $TemplateCacheProvider,
2611                 $templateRequest: $TemplateRequestProvider,
2612                 $$testability: $$TestabilityProvider,
2613                 $timeout: $TimeoutProvider,
2614                 $window: $WindowProvider,
2615                 $$rAF: $$RAFProvider,
2616                 $$jqLite: $$jqLiteProvider,
2617                 $$HashMap: $$HashMapProvider,
2618                 $$cookieReader: $$CookieReaderProvider
2619               });
2620             }
2621           ]);
2622         }
2623
2624         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2625          *     Any commits to this file should be reviewed with security in mind.  *
2626          *   Changes to this file can potentially create security vulnerabilities. *
2627          *          An approval from 2 Core members with history of modifying      *
2628          *                         this file is required.                          *
2629          *                                                                         *
2630          *  Does the change somehow allow for arbitrary javascript to be executed? *
2631          *    Or allows for someone to change the prototype of built-in objects?   *
2632          *     Or gives undesired access to variables likes document or window?    *
2633          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2634
2635         /* global JQLitePrototype: true,
2636           addEventListenerFn: true,
2637           removeEventListenerFn: true,
2638           BOOLEAN_ATTR: true,
2639           ALIASED_ATTR: true,
2640         */
2641
2642         //////////////////////////////////
2643         //JQLite
2644         //////////////////////////////////
2645
2646         /**
2647          * @ngdoc function
2648          * @name angular.element
2649          * @module ng
2650          * @kind function
2651          *
2652          * @description
2653          * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2654          *
2655          * If jQuery is available, `angular.element` is an alias for the
2656          * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2657          * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2658          *
2659          * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2660          * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2661          * commonly needed functionality with the goal of having a very small footprint.</div>
2662          *
2663          * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
2664          *
2665          * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2666          * jqLite; they are never raw DOM references.</div>
2667          *
2668          * ## Angular's jqLite
2669          * jqLite provides only the following jQuery methods:
2670          *
2671          * - [`addClass()`](http://api.jquery.com/addClass/)
2672          * - [`after()`](http://api.jquery.com/after/)
2673          * - [`append()`](http://api.jquery.com/append/)
2674          * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2675          * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2676          * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2677          * - [`clone()`](http://api.jquery.com/clone/)
2678          * - [`contents()`](http://api.jquery.com/contents/)
2679          * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
2680          * - [`data()`](http://api.jquery.com/data/)
2681          * - [`detach()`](http://api.jquery.com/detach/)
2682          * - [`empty()`](http://api.jquery.com/empty/)
2683          * - [`eq()`](http://api.jquery.com/eq/)
2684          * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2685          * - [`hasClass()`](http://api.jquery.com/hasClass/)
2686          * - [`html()`](http://api.jquery.com/html/)
2687          * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2688          * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2689          * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
2690          * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2691          * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2692          * - [`prepend()`](http://api.jquery.com/prepend/)
2693          * - [`prop()`](http://api.jquery.com/prop/)
2694          * - [`ready()`](http://api.jquery.com/ready/)
2695          * - [`remove()`](http://api.jquery.com/remove/)
2696          * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2697          * - [`removeClass()`](http://api.jquery.com/removeClass/)
2698          * - [`removeData()`](http://api.jquery.com/removeData/)
2699          * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2700          * - [`text()`](http://api.jquery.com/text/)
2701          * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2702          * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2703          * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
2704          * - [`val()`](http://api.jquery.com/val/)
2705          * - [`wrap()`](http://api.jquery.com/wrap/)
2706          *
2707          * ## jQuery/jqLite Extras
2708          * Angular also provides the following additional methods and events to both jQuery and jqLite:
2709          *
2710          * ### Events
2711          * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2712          *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2713          *    element before it is removed.
2714          *
2715          * ### Methods
2716          * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2717          *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2718          *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2719          *   `'ngModel'`).
2720          * - `injector()` - retrieves the injector of the current element or its parent.
2721          * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2722          *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2723          *   be enabled.
2724          * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2725          *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2726          *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2727          *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2728          * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2729          *   parent element is reached.
2730          *
2731          * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2732          * @returns {Object} jQuery object.
2733          */
2734
2735         JQLite.expando = 'ng339';
2736
2737         var jqCache = JQLite.cache = {},
2738             jqId = 1,
2739             addEventListenerFn = function(element, type, fn) {
2740               element.addEventListener(type, fn, false);
2741             },
2742             removeEventListenerFn = function(element, type, fn) {
2743               element.removeEventListener(type, fn, false);
2744             };
2745
2746         /*
2747          * !!! This is an undocumented "private" function !!!
2748          */
2749         JQLite._data = function(node) {
2750           //jQuery always returns an object on cache miss
2751           return this.cache[node[this.expando]] || {};
2752         };
2753
2754         function jqNextId() { return ++jqId; }
2755
2756
2757         var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2758         var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2759         var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2760         var jqLiteMinErr = minErr('jqLite');
2761
2762         /**
2763          * Converts snake_case to camelCase.
2764          * Also there is special case for Moz prefix starting with upper case letter.
2765          * @param name Name to normalize
2766          */
2767         function camelCase(name) {
2768           return name.
2769             replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2770               return offset ? letter.toUpperCase() : letter;
2771             }).
2772             replace(MOZ_HACK_REGEXP, 'Moz$1');
2773         }
2774
2775         var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
2776         var HTML_REGEXP = /<|&#?\w+;/;
2777         var TAG_NAME_REGEXP = /<([\w:-]+)/;
2778         var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
2779
2780         var wrapMap = {
2781           'option': [1, '<select multiple="multiple">', '</select>'],
2782
2783           'thead': [1, '<table>', '</table>'],
2784           'col': [2, '<table><colgroup>', '</colgroup></table>'],
2785           'tr': [2, '<table><tbody>', '</tbody></table>'],
2786           'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2787           '_default': [0, "", ""]
2788         };
2789
2790         wrapMap.optgroup = wrapMap.option;
2791         wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2792         wrapMap.th = wrapMap.td;
2793
2794
2795         function jqLiteIsTextNode(html) {
2796           return !HTML_REGEXP.test(html);
2797         }
2798
2799         function jqLiteAcceptsData(node) {
2800           // The window object can accept data but has no nodeType
2801           // Otherwise we are only interested in elements (1) and documents (9)
2802           var nodeType = node.nodeType;
2803           return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2804         }
2805
2806         function jqLiteHasData(node) {
2807           for (var key in jqCache[node.ng339]) {
2808             return true;
2809           }
2810           return false;
2811         }
2812
2813         function jqLiteBuildFragment(html, context) {
2814           var tmp, tag, wrap,
2815               fragment = context.createDocumentFragment(),
2816               nodes = [], i;
2817
2818           if (jqLiteIsTextNode(html)) {
2819             // Convert non-html into a text node
2820             nodes.push(context.createTextNode(html));
2821           } else {
2822             // Convert html into DOM nodes
2823             tmp = tmp || fragment.appendChild(context.createElement("div"));
2824             tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2825             wrap = wrapMap[tag] || wrapMap._default;
2826             tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2827
2828             // Descend through wrappers to the right content
2829             i = wrap[0];
2830             while (i--) {
2831               tmp = tmp.lastChild;
2832             }
2833
2834             nodes = concat(nodes, tmp.childNodes);
2835
2836             tmp = fragment.firstChild;
2837             tmp.textContent = "";
2838           }
2839
2840           // Remove wrapper from fragment
2841           fragment.textContent = "";
2842           fragment.innerHTML = ""; // Clear inner HTML
2843           forEach(nodes, function(node) {
2844             fragment.appendChild(node);
2845           });
2846
2847           return fragment;
2848         }
2849
2850         function jqLiteParseHTML(html, context) {
2851           context = context || document;
2852           var parsed;
2853
2854           if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2855             return [context.createElement(parsed[1])];
2856           }
2857
2858           if ((parsed = jqLiteBuildFragment(html, context))) {
2859             return parsed.childNodes;
2860           }
2861
2862           return [];
2863         }
2864
2865
2866         // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2867         var jqLiteContains = Node.prototype.contains || function(arg) {
2868           // jshint bitwise: false
2869           return !!(this.compareDocumentPosition(arg) & 16);
2870           // jshint bitwise: true
2871         };
2872
2873         /////////////////////////////////////////////
2874         function JQLite(element) {
2875           if (element instanceof JQLite) {
2876             return element;
2877           }
2878
2879           var argIsString;
2880
2881           if (isString(element)) {
2882             element = trim(element);
2883             argIsString = true;
2884           }
2885           if (!(this instanceof JQLite)) {
2886             if (argIsString && element.charAt(0) != '<') {
2887               throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2888             }
2889             return new JQLite(element);
2890           }
2891
2892           if (argIsString) {
2893             jqLiteAddNodes(this, jqLiteParseHTML(element));
2894           } else {
2895             jqLiteAddNodes(this, element);
2896           }
2897         }
2898
2899         function jqLiteClone(element) {
2900           return element.cloneNode(true);
2901         }
2902
2903         function jqLiteDealoc(element, onlyDescendants) {
2904           if (!onlyDescendants) jqLiteRemoveData(element);
2905
2906           if (element.querySelectorAll) {
2907             var descendants = element.querySelectorAll('*');
2908             for (var i = 0, l = descendants.length; i < l; i++) {
2909               jqLiteRemoveData(descendants[i]);
2910             }
2911           }
2912         }
2913
2914         function jqLiteOff(element, type, fn, unsupported) {
2915           if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2916
2917           var expandoStore = jqLiteExpandoStore(element);
2918           var events = expandoStore && expandoStore.events;
2919           var handle = expandoStore && expandoStore.handle;
2920
2921           if (!handle) return; //no listeners registered
2922
2923           if (!type) {
2924             for (type in events) {
2925               if (type !== '$destroy') {
2926                 removeEventListenerFn(element, type, handle);
2927               }
2928               delete events[type];
2929             }
2930           } else {
2931
2932             var removeHandler = function(type) {
2933               var listenerFns = events[type];
2934               if (isDefined(fn)) {
2935                 arrayRemove(listenerFns || [], fn);
2936               }
2937               if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
2938                 removeEventListenerFn(element, type, handle);
2939                 delete events[type];
2940               }
2941             };
2942
2943             forEach(type.split(' '), function(type) {
2944               removeHandler(type);
2945               if (MOUSE_EVENT_MAP[type]) {
2946                 removeHandler(MOUSE_EVENT_MAP[type]);
2947               }
2948             });
2949           }
2950         }
2951
2952         function jqLiteRemoveData(element, name) {
2953           var expandoId = element.ng339;
2954           var expandoStore = expandoId && jqCache[expandoId];
2955
2956           if (expandoStore) {
2957             if (name) {
2958               delete expandoStore.data[name];
2959               return;
2960             }
2961
2962             if (expandoStore.handle) {
2963               if (expandoStore.events.$destroy) {
2964                 expandoStore.handle({}, '$destroy');
2965               }
2966               jqLiteOff(element);
2967             }
2968             delete jqCache[expandoId];
2969             element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2970           }
2971         }
2972
2973
2974         function jqLiteExpandoStore(element, createIfNecessary) {
2975           var expandoId = element.ng339,
2976               expandoStore = expandoId && jqCache[expandoId];
2977
2978           if (createIfNecessary && !expandoStore) {
2979             element.ng339 = expandoId = jqNextId();
2980             expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
2981           }
2982
2983           return expandoStore;
2984         }
2985
2986
2987         function jqLiteData(element, key, value) {
2988           if (jqLiteAcceptsData(element)) {
2989
2990             var isSimpleSetter = isDefined(value);
2991             var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
2992             var massGetter = !key;
2993             var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
2994             var data = expandoStore && expandoStore.data;
2995
2996             if (isSimpleSetter) { // data('key', value)
2997               data[key] = value;
2998             } else {
2999               if (massGetter) {  // data()
3000                 return data;
3001               } else {
3002                 if (isSimpleGetter) { // data('key')
3003                   // don't force creation of expandoStore if it doesn't exist yet
3004                   return data && data[key];
3005                 } else { // mass-setter: data({key1: val1, key2: val2})
3006                   extend(data, key);
3007                 }
3008               }
3009             }
3010           }
3011         }
3012
3013         function jqLiteHasClass(element, selector) {
3014           if (!element.getAttribute) return false;
3015           return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
3016               indexOf(" " + selector + " ") > -1);
3017         }
3018
3019         function jqLiteRemoveClass(element, cssClasses) {
3020           if (cssClasses && element.setAttribute) {
3021             forEach(cssClasses.split(' '), function(cssClass) {
3022               element.setAttribute('class', trim(
3023                   (" " + (element.getAttribute('class') || '') + " ")
3024                   .replace(/[\n\t]/g, " ")
3025                   .replace(" " + trim(cssClass) + " ", " "))
3026               );
3027             });
3028           }
3029         }
3030
3031         function jqLiteAddClass(element, cssClasses) {
3032           if (cssClasses && element.setAttribute) {
3033             var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
3034                                     .replace(/[\n\t]/g, " ");
3035
3036             forEach(cssClasses.split(' '), function(cssClass) {
3037               cssClass = trim(cssClass);
3038               if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
3039                 existingClasses += cssClass + ' ';
3040               }
3041             });
3042
3043             element.setAttribute('class', trim(existingClasses));
3044           }
3045         }
3046
3047
3048         function jqLiteAddNodes(root, elements) {
3049           // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
3050
3051           if (elements) {
3052
3053             // if a Node (the most common case)
3054             if (elements.nodeType) {
3055               root[root.length++] = elements;
3056             } else {
3057               var length = elements.length;
3058
3059               // if an Array or NodeList and not a Window
3060               if (typeof length === 'number' && elements.window !== elements) {
3061                 if (length) {
3062                   for (var i = 0; i < length; i++) {
3063                     root[root.length++] = elements[i];
3064                   }
3065                 }
3066               } else {
3067                 root[root.length++] = elements;
3068               }
3069             }
3070           }
3071         }
3072
3073
3074         function jqLiteController(element, name) {
3075           return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
3076         }
3077
3078         function jqLiteInheritedData(element, name, value) {
3079           // if element is the document object work with the html element instead
3080           // this makes $(document).scope() possible
3081           if (element.nodeType == NODE_TYPE_DOCUMENT) {
3082             element = element.documentElement;
3083           }
3084           var names = isArray(name) ? name : [name];
3085
3086           while (element) {
3087             for (var i = 0, ii = names.length; i < ii; i++) {
3088               if (isDefined(value = jqLite.data(element, names[i]))) return value;
3089             }
3090
3091             // If dealing with a document fragment node with a host element, and no parent, use the host
3092             // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
3093             // to lookup parent controllers.
3094             element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
3095           }
3096         }
3097
3098         function jqLiteEmpty(element) {
3099           jqLiteDealoc(element, true);
3100           while (element.firstChild) {
3101             element.removeChild(element.firstChild);
3102           }
3103         }
3104
3105         function jqLiteRemove(element, keepData) {
3106           if (!keepData) jqLiteDealoc(element);
3107           var parent = element.parentNode;
3108           if (parent) parent.removeChild(element);
3109         }
3110
3111
3112         function jqLiteDocumentLoaded(action, win) {
3113           win = win || window;
3114           if (win.document.readyState === 'complete') {
3115             // Force the action to be run async for consistent behaviour
3116             // from the action's point of view
3117             // i.e. it will definitely not be in a $apply
3118             win.setTimeout(action);
3119           } else {
3120             // No need to unbind this handler as load is only ever called once
3121             jqLite(win).on('load', action);
3122           }
3123         }
3124
3125         //////////////////////////////////////////
3126         // Functions which are declared directly.
3127         //////////////////////////////////////////
3128         var JQLitePrototype = JQLite.prototype = {
3129           ready: function(fn) {
3130             var fired = false;
3131
3132             function trigger() {
3133               if (fired) return;
3134               fired = true;
3135               fn();
3136             }
3137
3138             // check if document is already loaded
3139             if (document.readyState === 'complete') {
3140               setTimeout(trigger);
3141             } else {
3142               this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
3143               // we can not use jqLite since we are not done loading and jQuery could be loaded later.
3144               // jshint -W064
3145               JQLite(window).on('load', trigger); // fallback to window.onload for others
3146               // jshint +W064
3147             }
3148           },
3149           toString: function() {
3150             var value = [];
3151             forEach(this, function(e) { value.push('' + e);});
3152             return '[' + value.join(', ') + ']';
3153           },
3154
3155           eq: function(index) {
3156               return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
3157           },
3158
3159           length: 0,
3160           push: push,
3161           sort: [].sort,
3162           splice: [].splice
3163         };
3164
3165         //////////////////////////////////////////
3166         // Functions iterating getter/setters.
3167         // these functions return self on setter and
3168         // value on get.
3169         //////////////////////////////////////////
3170         var BOOLEAN_ATTR = {};
3171         forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
3172           BOOLEAN_ATTR[lowercase(value)] = value;
3173         });
3174         var BOOLEAN_ELEMENTS = {};
3175         forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
3176           BOOLEAN_ELEMENTS[value] = true;
3177         });
3178         var ALIASED_ATTR = {
3179           'ngMinlength': 'minlength',
3180           'ngMaxlength': 'maxlength',
3181           'ngMin': 'min',
3182           'ngMax': 'max',
3183           'ngPattern': 'pattern'
3184         };
3185
3186         function getBooleanAttrName(element, name) {
3187           // check dom last since we will most likely fail on name
3188           var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
3189
3190           // booleanAttr is here twice to minimize DOM access
3191           return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
3192         }
3193
3194         function getAliasedAttrName(name) {
3195           return ALIASED_ATTR[name];
3196         }
3197
3198         forEach({
3199           data: jqLiteData,
3200           removeData: jqLiteRemoveData,
3201           hasData: jqLiteHasData
3202         }, function(fn, name) {
3203           JQLite[name] = fn;
3204         });
3205
3206         forEach({
3207           data: jqLiteData,
3208           inheritedData: jqLiteInheritedData,
3209
3210           scope: function(element) {
3211             // Can't use jqLiteData here directly so we stay compatible with jQuery!
3212             return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
3213           },
3214
3215           isolateScope: function(element) {
3216             // Can't use jqLiteData here directly so we stay compatible with jQuery!
3217             return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
3218           },
3219
3220           controller: jqLiteController,
3221
3222           injector: function(element) {
3223             return jqLiteInheritedData(element, '$injector');
3224           },
3225
3226           removeAttr: function(element, name) {
3227             element.removeAttribute(name);
3228           },
3229
3230           hasClass: jqLiteHasClass,
3231
3232           css: function(element, name, value) {
3233             name = camelCase(name);
3234
3235             if (isDefined(value)) {
3236               element.style[name] = value;
3237             } else {
3238               return element.style[name];
3239             }
3240           },
3241
3242           attr: function(element, name, value) {
3243             var nodeType = element.nodeType;
3244             if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
3245               return;
3246             }
3247             var lowercasedName = lowercase(name);
3248             if (BOOLEAN_ATTR[lowercasedName]) {
3249               if (isDefined(value)) {
3250                 if (!!value) {
3251                   element[name] = true;
3252                   element.setAttribute(name, lowercasedName);
3253                 } else {
3254                   element[name] = false;
3255                   element.removeAttribute(lowercasedName);
3256                 }
3257               } else {
3258                 return (element[name] ||
3259                          (element.attributes.getNamedItem(name) || noop).specified)
3260                        ? lowercasedName
3261                        : undefined;
3262               }
3263             } else if (isDefined(value)) {
3264               element.setAttribute(name, value);
3265             } else if (element.getAttribute) {
3266               // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
3267               // some elements (e.g. Document) don't have get attribute, so return undefined
3268               var ret = element.getAttribute(name, 2);
3269               // normalize non-existing attributes to undefined (as jQuery)
3270               return ret === null ? undefined : ret;
3271             }
3272           },
3273
3274           prop: function(element, name, value) {
3275             if (isDefined(value)) {
3276               element[name] = value;
3277             } else {
3278               return element[name];
3279             }
3280           },
3281
3282           text: (function() {
3283             getText.$dv = '';
3284             return getText;
3285
3286             function getText(element, value) {
3287               if (isUndefined(value)) {
3288                 var nodeType = element.nodeType;
3289                 return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
3290               }
3291               element.textContent = value;
3292             }
3293           })(),
3294
3295           val: function(element, value) {
3296             if (isUndefined(value)) {
3297               if (element.multiple && nodeName_(element) === 'select') {
3298                 var result = [];
3299                 forEach(element.options, function(option) {
3300                   if (option.selected) {
3301                     result.push(option.value || option.text);
3302                   }
3303                 });
3304                 return result.length === 0 ? null : result;
3305               }
3306               return element.value;
3307             }
3308             element.value = value;
3309           },
3310
3311           html: function(element, value) {
3312             if (isUndefined(value)) {
3313               return element.innerHTML;
3314             }
3315             jqLiteDealoc(element, true);
3316             element.innerHTML = value;
3317           },
3318
3319           empty: jqLiteEmpty
3320         }, function(fn, name) {
3321           /**
3322            * Properties: writes return selection, reads return first value
3323            */
3324           JQLite.prototype[name] = function(arg1, arg2) {
3325             var i, key;
3326             var nodeCount = this.length;
3327
3328             // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
3329             // in a way that survives minification.
3330             // jqLiteEmpty takes no arguments but is a setter.
3331             if (fn !== jqLiteEmpty &&
3332                 (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
3333               if (isObject(arg1)) {
3334
3335                 // we are a write, but the object properties are the key/values
3336                 for (i = 0; i < nodeCount; i++) {
3337                   if (fn === jqLiteData) {
3338                     // data() takes the whole object in jQuery
3339                     fn(this[i], arg1);
3340                   } else {
3341                     for (key in arg1) {
3342                       fn(this[i], key, arg1[key]);
3343                     }
3344                   }
3345                 }
3346                 // return self for chaining
3347                 return this;
3348               } else {
3349                 // we are a read, so read the first child.
3350                 // TODO: do we still need this?
3351                 var value = fn.$dv;
3352                 // Only if we have $dv do we iterate over all, otherwise it is just the first element.
3353                 var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
3354                 for (var j = 0; j < jj; j++) {
3355                   var nodeValue = fn(this[j], arg1, arg2);
3356                   value = value ? value + nodeValue : nodeValue;
3357                 }
3358                 return value;
3359               }
3360             } else {
3361               // we are a write, so apply to all children
3362               for (i = 0; i < nodeCount; i++) {
3363                 fn(this[i], arg1, arg2);
3364               }
3365               // return self for chaining
3366               return this;
3367             }
3368           };
3369         });
3370
3371         function createEventHandler(element, events) {
3372           var eventHandler = function(event, type) {
3373             // jQuery specific api
3374             event.isDefaultPrevented = function() {
3375               return event.defaultPrevented;
3376             };
3377
3378             var eventFns = events[type || event.type];
3379             var eventFnsLength = eventFns ? eventFns.length : 0;
3380
3381             if (!eventFnsLength) return;
3382
3383             if (isUndefined(event.immediatePropagationStopped)) {
3384               var originalStopImmediatePropagation = event.stopImmediatePropagation;
3385               event.stopImmediatePropagation = function() {
3386                 event.immediatePropagationStopped = true;
3387
3388                 if (event.stopPropagation) {
3389                   event.stopPropagation();
3390                 }
3391
3392                 if (originalStopImmediatePropagation) {
3393                   originalStopImmediatePropagation.call(event);
3394                 }
3395               };
3396             }
3397
3398             event.isImmediatePropagationStopped = function() {
3399               return event.immediatePropagationStopped === true;
3400             };
3401
3402             // Some events have special handlers that wrap the real handler
3403             var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
3404
3405             // Copy event handlers in case event handlers array is modified during execution.
3406             if ((eventFnsLength > 1)) {
3407               eventFns = shallowCopy(eventFns);
3408             }
3409
3410             for (var i = 0; i < eventFnsLength; i++) {
3411               if (!event.isImmediatePropagationStopped()) {
3412                 handlerWrapper(element, event, eventFns[i]);
3413               }
3414             }
3415           };
3416
3417           // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3418           //       events on `element`
3419           eventHandler.elem = element;
3420           return eventHandler;
3421         }
3422
3423         function defaultHandlerWrapper(element, event, handler) {
3424           handler.call(element, event);
3425         }
3426
3427         function specialMouseHandlerWrapper(target, event, handler) {
3428           // Refer to jQuery's implementation of mouseenter & mouseleave
3429           // Read about mouseenter and mouseleave:
3430           // http://www.quirksmode.org/js/events_mouse.html#link8
3431           var related = event.relatedTarget;
3432           // For mousenter/leave call the handler if related is outside the target.
3433           // NB: No relatedTarget if the mouse left/entered the browser window
3434           if (!related || (related !== target && !jqLiteContains.call(target, related))) {
3435             handler.call(target, event);
3436           }
3437         }
3438
3439         //////////////////////////////////////////
3440         // Functions iterating traversal.
3441         // These functions chain results into a single
3442         // selector.
3443         //////////////////////////////////////////
3444         forEach({
3445           removeData: jqLiteRemoveData,
3446
3447           on: function jqLiteOn(element, type, fn, unsupported) {
3448             if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3449
3450             // Do not add event handlers to non-elements because they will not be cleaned up.
3451             if (!jqLiteAcceptsData(element)) {
3452               return;
3453             }
3454
3455             var expandoStore = jqLiteExpandoStore(element, true);
3456             var events = expandoStore.events;
3457             var handle = expandoStore.handle;
3458
3459             if (!handle) {
3460               handle = expandoStore.handle = createEventHandler(element, events);
3461             }
3462
3463             // http://jsperf.com/string-indexof-vs-split
3464             var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3465             var i = types.length;
3466
3467             var addHandler = function(type, specialHandlerWrapper, noEventListener) {
3468               var eventFns = events[type];
3469
3470               if (!eventFns) {
3471                 eventFns = events[type] = [];
3472                 eventFns.specialHandlerWrapper = specialHandlerWrapper;
3473                 if (type !== '$destroy' && !noEventListener) {
3474                   addEventListenerFn(element, type, handle);
3475                 }
3476               }
3477
3478               eventFns.push(fn);
3479             };
3480
3481             while (i--) {
3482               type = types[i];
3483               if (MOUSE_EVENT_MAP[type]) {
3484                 addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
3485                 addHandler(type, undefined, true);
3486               } else {
3487                 addHandler(type);
3488               }
3489             }
3490           },
3491
3492           off: jqLiteOff,
3493
3494           one: function(element, type, fn) {
3495             element = jqLite(element);
3496
3497             //add the listener twice so that when it is called
3498             //you can remove the original function and still be
3499             //able to call element.off(ev, fn) normally
3500             element.on(type, function onFn() {
3501               element.off(type, fn);
3502               element.off(type, onFn);
3503             });
3504             element.on(type, fn);
3505           },
3506
3507           replaceWith: function(element, replaceNode) {
3508             var index, parent = element.parentNode;
3509             jqLiteDealoc(element);
3510             forEach(new JQLite(replaceNode), function(node) {
3511               if (index) {
3512                 parent.insertBefore(node, index.nextSibling);
3513               } else {
3514                 parent.replaceChild(node, element);
3515               }
3516               index = node;
3517             });
3518           },
3519
3520           children: function(element) {
3521             var children = [];
3522             forEach(element.childNodes, function(element) {
3523               if (element.nodeType === NODE_TYPE_ELEMENT) {
3524                 children.push(element);
3525               }
3526             });
3527             return children;
3528           },
3529
3530           contents: function(element) {
3531             return element.contentDocument || element.childNodes || [];
3532           },
3533
3534           append: function(element, node) {
3535             var nodeType = element.nodeType;
3536             if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3537
3538             node = new JQLite(node);
3539
3540             for (var i = 0, ii = node.length; i < ii; i++) {
3541               var child = node[i];
3542               element.appendChild(child);
3543             }
3544           },
3545
3546           prepend: function(element, node) {
3547             if (element.nodeType === NODE_TYPE_ELEMENT) {
3548               var index = element.firstChild;
3549               forEach(new JQLite(node), function(child) {
3550                 element.insertBefore(child, index);
3551               });
3552             }
3553           },
3554
3555           wrap: function(element, wrapNode) {
3556             wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3557             var parent = element.parentNode;
3558             if (parent) {
3559               parent.replaceChild(wrapNode, element);
3560             }
3561             wrapNode.appendChild(element);
3562           },
3563
3564           remove: jqLiteRemove,
3565
3566           detach: function(element) {
3567             jqLiteRemove(element, true);
3568           },
3569
3570           after: function(element, newElement) {
3571             var index = element, parent = element.parentNode;
3572             newElement = new JQLite(newElement);
3573
3574             for (var i = 0, ii = newElement.length; i < ii; i++) {
3575               var node = newElement[i];
3576               parent.insertBefore(node, index.nextSibling);
3577               index = node;
3578             }
3579           },
3580
3581           addClass: jqLiteAddClass,
3582           removeClass: jqLiteRemoveClass,
3583
3584           toggleClass: function(element, selector, condition) {
3585             if (selector) {
3586               forEach(selector.split(' '), function(className) {
3587                 var classCondition = condition;
3588                 if (isUndefined(classCondition)) {
3589                   classCondition = !jqLiteHasClass(element, className);
3590                 }
3591                 (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3592               });
3593             }
3594           },
3595
3596           parent: function(element) {
3597             var parent = element.parentNode;
3598             return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3599           },
3600
3601           next: function(element) {
3602             return element.nextElementSibling;
3603           },
3604
3605           find: function(element, selector) {
3606             if (element.getElementsByTagName) {
3607               return element.getElementsByTagName(selector);
3608             } else {
3609               return [];
3610             }
3611           },
3612
3613           clone: jqLiteClone,
3614
3615           triggerHandler: function(element, event, extraParameters) {
3616
3617             var dummyEvent, eventFnsCopy, handlerArgs;
3618             var eventName = event.type || event;
3619             var expandoStore = jqLiteExpandoStore(element);
3620             var events = expandoStore && expandoStore.events;
3621             var eventFns = events && events[eventName];
3622
3623             if (eventFns) {
3624               // Create a dummy event to pass to the handlers
3625               dummyEvent = {
3626                 preventDefault: function() { this.defaultPrevented = true; },
3627                 isDefaultPrevented: function() { return this.defaultPrevented === true; },
3628                 stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3629                 isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3630                 stopPropagation: noop,
3631                 type: eventName,
3632                 target: element
3633               };
3634
3635               // If a custom event was provided then extend our dummy event with it
3636               if (event.type) {
3637                 dummyEvent = extend(dummyEvent, event);
3638               }
3639
3640               // Copy event handlers in case event handlers array is modified during execution.
3641               eventFnsCopy = shallowCopy(eventFns);
3642               handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3643
3644               forEach(eventFnsCopy, function(fn) {
3645                 if (!dummyEvent.isImmediatePropagationStopped()) {
3646                   fn.apply(element, handlerArgs);
3647                 }
3648               });
3649             }
3650           }
3651         }, function(fn, name) {
3652           /**
3653            * chaining functions
3654            */
3655           JQLite.prototype[name] = function(arg1, arg2, arg3) {
3656             var value;
3657
3658             for (var i = 0, ii = this.length; i < ii; i++) {
3659               if (isUndefined(value)) {
3660                 value = fn(this[i], arg1, arg2, arg3);
3661                 if (isDefined(value)) {
3662                   // any function which returns a value needs to be wrapped
3663                   value = jqLite(value);
3664                 }
3665               } else {
3666                 jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3667               }
3668             }
3669             return isDefined(value) ? value : this;
3670           };
3671
3672           // bind legacy bind/unbind to on/off
3673           JQLite.prototype.bind = JQLite.prototype.on;
3674           JQLite.prototype.unbind = JQLite.prototype.off;
3675         });
3676
3677
3678         // Provider for private $$jqLite service
3679         function $$jqLiteProvider() {
3680           this.$get = function $$jqLite() {
3681             return extend(JQLite, {
3682               hasClass: function(node, classes) {
3683                 if (node.attr) node = node[0];
3684                 return jqLiteHasClass(node, classes);
3685               },
3686               addClass: function(node, classes) {
3687                 if (node.attr) node = node[0];
3688                 return jqLiteAddClass(node, classes);
3689               },
3690               removeClass: function(node, classes) {
3691                 if (node.attr) node = node[0];
3692                 return jqLiteRemoveClass(node, classes);
3693               }
3694             });
3695           };
3696         }
3697
3698         /**
3699          * Computes a hash of an 'obj'.
3700          * Hash of a:
3701          *  string is string
3702          *  number is number as string
3703          *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3704          *         that is also assigned to the $$hashKey property of the object.
3705          *
3706          * @param obj
3707          * @returns {string} hash string such that the same input will have the same hash string.
3708          *         The resulting string key is in 'type:hashKey' format.
3709          */
3710         function hashKey(obj, nextUidFn) {
3711           var key = obj && obj.$$hashKey;
3712
3713           if (key) {
3714             if (typeof key === 'function') {
3715               key = obj.$$hashKey();
3716             }
3717             return key;
3718           }
3719
3720           var objType = typeof obj;
3721           if (objType == 'function' || (objType == 'object' && obj !== null)) {
3722             key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3723           } else {
3724             key = objType + ':' + obj;
3725           }
3726
3727           return key;
3728         }
3729
3730         /**
3731          * HashMap which can use objects as keys
3732          */
3733         function HashMap(array, isolatedUid) {
3734           if (isolatedUid) {
3735             var uid = 0;
3736             this.nextUid = function() {
3737               return ++uid;
3738             };
3739           }
3740           forEach(array, this.put, this);
3741         }
3742         HashMap.prototype = {
3743           /**
3744            * Store key value pair
3745            * @param key key to store can be any type
3746            * @param value value to store can be any type
3747            */
3748           put: function(key, value) {
3749             this[hashKey(key, this.nextUid)] = value;
3750           },
3751
3752           /**
3753            * @param key
3754            * @returns {Object} the value for the key
3755            */
3756           get: function(key) {
3757             return this[hashKey(key, this.nextUid)];
3758           },
3759
3760           /**
3761            * Remove the key/value pair
3762            * @param key
3763            */
3764           remove: function(key) {
3765             var value = this[key = hashKey(key, this.nextUid)];
3766             delete this[key];
3767             return value;
3768           }
3769         };
3770
3771         var $$HashMapProvider = [function() {
3772           this.$get = [function() {
3773             return HashMap;
3774           }];
3775         }];
3776
3777         /**
3778          * @ngdoc function
3779          * @module ng
3780          * @name angular.injector
3781          * @kind function
3782          *
3783          * @description
3784          * Creates an injector object that can be used for retrieving services as well as for
3785          * dependency injection (see {@link guide/di dependency injection}).
3786          *
3787          * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3788          *     {@link angular.module}. The `ng` module must be explicitly added.
3789          * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3790          *     disallows argument name annotation inference.
3791          * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3792          *
3793          * @example
3794          * Typical usage
3795          * ```js
3796          *   // create an injector
3797          *   var $injector = angular.injector(['ng']);
3798          *
3799          *   // use the injector to kick off your application
3800          *   // use the type inference to auto inject arguments, or use implicit injection
3801          *   $injector.invoke(function($rootScope, $compile, $document) {
3802          *     $compile($document)($rootScope);
3803          *     $rootScope.$digest();
3804          *   });
3805          * ```
3806          *
3807          * Sometimes you want to get access to the injector of a currently running Angular app
3808          * from outside Angular. Perhaps, you want to inject and compile some markup after the
3809          * application has been bootstrapped. You can do this using the extra `injector()` added
3810          * to JQuery/jqLite elements. See {@link angular.element}.
3811          *
3812          * *This is fairly rare but could be the case if a third party library is injecting the
3813          * markup.*
3814          *
3815          * In the following example a new block of HTML containing a `ng-controller`
3816          * directive is added to the end of the document body by JQuery. We then compile and link
3817          * it into the current AngularJS scope.
3818          *
3819          * ```js
3820          * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3821          * $(document.body).append($div);
3822          *
3823          * angular.element(document).injector().invoke(function($compile) {
3824          *   var scope = angular.element($div).scope();
3825          *   $compile($div)(scope);
3826          * });
3827          * ```
3828          */
3829
3830
3831         /**
3832          * @ngdoc module
3833          * @name auto
3834          * @description
3835          *
3836          * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3837          */
3838
3839         var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
3840         var FN_ARG_SPLIT = /,/;
3841         var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3842         var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3843         var $injectorMinErr = minErr('$injector');
3844
3845         function anonFn(fn) {
3846           // For anonymous functions, showing at the very least the function signature can help in
3847           // debugging.
3848           var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3849               args = fnText.match(FN_ARGS);
3850           if (args) {
3851             return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3852           }
3853           return 'fn';
3854         }
3855
3856         function annotate(fn, strictDi, name) {
3857           var $inject,
3858               fnText,
3859               argDecl,
3860               last;
3861
3862           if (typeof fn === 'function') {
3863             if (!($inject = fn.$inject)) {
3864               $inject = [];
3865               if (fn.length) {
3866                 if (strictDi) {
3867                   if (!isString(name) || !name) {
3868                     name = fn.name || anonFn(fn);
3869                   }
3870                   throw $injectorMinErr('strictdi',
3871                     '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3872                 }
3873                 fnText = fn.toString().replace(STRIP_COMMENTS, '');
3874                 argDecl = fnText.match(FN_ARGS);
3875                 forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3876                   arg.replace(FN_ARG, function(all, underscore, name) {
3877                     $inject.push(name);
3878                   });
3879                 });
3880               }
3881               fn.$inject = $inject;
3882             }
3883           } else if (isArray(fn)) {
3884             last = fn.length - 1;
3885             assertArgFn(fn[last], 'fn');
3886             $inject = fn.slice(0, last);
3887           } else {
3888             assertArgFn(fn, 'fn', true);
3889           }
3890           return $inject;
3891         }
3892
3893         ///////////////////////////////////////
3894
3895         /**
3896          * @ngdoc service
3897          * @name $injector
3898          *
3899          * @description
3900          *
3901          * `$injector` is used to retrieve object instances as defined by
3902          * {@link auto.$provide provider}, instantiate types, invoke methods,
3903          * and load modules.
3904          *
3905          * The following always holds true:
3906          *
3907          * ```js
3908          *   var $injector = angular.injector();
3909          *   expect($injector.get('$injector')).toBe($injector);
3910          *   expect($injector.invoke(function($injector) {
3911          *     return $injector;
3912          *   })).toBe($injector);
3913          * ```
3914          *
3915          * # Injection Function Annotation
3916          *
3917          * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3918          * following are all valid ways of annotating function with injection arguments and are equivalent.
3919          *
3920          * ```js
3921          *   // inferred (only works if code not minified/obfuscated)
3922          *   $injector.invoke(function(serviceA){});
3923          *
3924          *   // annotated
3925          *   function explicit(serviceA) {};
3926          *   explicit.$inject = ['serviceA'];
3927          *   $injector.invoke(explicit);
3928          *
3929          *   // inline
3930          *   $injector.invoke(['serviceA', function(serviceA){}]);
3931          * ```
3932          *
3933          * ## Inference
3934          *
3935          * In JavaScript calling `toString()` on a function returns the function definition. The definition
3936          * can then be parsed and the function arguments can be extracted. This method of discovering
3937          * annotations is disallowed when the injector is in strict mode.
3938          * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3939          * argument names.
3940          *
3941          * ## `$inject` Annotation
3942          * By adding an `$inject` property onto a function the injection parameters can be specified.
3943          *
3944          * ## Inline
3945          * As an array of injection names, where the last item in the array is the function to call.
3946          */
3947
3948         /**
3949          * @ngdoc method
3950          * @name $injector#get
3951          *
3952          * @description
3953          * Return an instance of the service.
3954          *
3955          * @param {string} name The name of the instance to retrieve.
3956          * @param {string=} caller An optional string to provide the origin of the function call for error messages.
3957          * @return {*} The instance.
3958          */
3959
3960         /**
3961          * @ngdoc method
3962          * @name $injector#invoke
3963          *
3964          * @description
3965          * Invoke the method and supply the method arguments from the `$injector`.
3966          *
3967          * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
3968          *   injected according to the {@link guide/di $inject Annotation} rules.
3969          * @param {Object=} self The `this` for the invoked method.
3970          * @param {Object=} locals Optional object. If preset then any argument names are read from this
3971          *                         object first, before the `$injector` is consulted.
3972          * @returns {*} the value returned by the invoked `fn` function.
3973          */
3974
3975         /**
3976          * @ngdoc method
3977          * @name $injector#has
3978          *
3979          * @description
3980          * Allows the user to query if the particular service exists.
3981          *
3982          * @param {string} name Name of the service to query.
3983          * @returns {boolean} `true` if injector has given service.
3984          */
3985
3986         /**
3987          * @ngdoc method
3988          * @name $injector#instantiate
3989          * @description
3990          * Create a new instance of JS type. The method takes a constructor function, invokes the new
3991          * operator, and supplies all of the arguments to the constructor function as specified by the
3992          * constructor annotation.
3993          *
3994          * @param {Function} Type Annotated constructor function.
3995          * @param {Object=} locals Optional object. If preset then any argument names are read from this
3996          * object first, before the `$injector` is consulted.
3997          * @returns {Object} new instance of `Type`.
3998          */
3999
4000         /**
4001          * @ngdoc method
4002          * @name $injector#annotate
4003          *
4004          * @description
4005          * Returns an array of service names which the function is requesting for injection. This API is
4006          * used by the injector to determine which services need to be injected into the function when the
4007          * function is invoked. There are three ways in which the function can be annotated with the needed
4008          * dependencies.
4009          *
4010          * # Argument names
4011          *
4012          * The simplest form is to extract the dependencies from the arguments of the function. This is done
4013          * by converting the function into a string using `toString()` method and extracting the argument
4014          * names.
4015          * ```js
4016          *   // Given
4017          *   function MyController($scope, $route) {
4018          *     // ...
4019          *   }
4020          *
4021          *   // Then
4022          *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4023          * ```
4024          *
4025          * You can disallow this method by using strict injection mode.
4026          *
4027          * This method does not work with code minification / obfuscation. For this reason the following
4028          * annotation strategies are supported.
4029          *
4030          * # The `$inject` property
4031          *
4032          * If a function has an `$inject` property and its value is an array of strings, then the strings
4033          * represent names of services to be injected into the function.
4034          * ```js
4035          *   // Given
4036          *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
4037          *     // ...
4038          *   }
4039          *   // Define function dependencies
4040          *   MyController['$inject'] = ['$scope', '$route'];
4041          *
4042          *   // Then
4043          *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4044          * ```
4045          *
4046          * # The array notation
4047          *
4048          * It is often desirable to inline Injected functions and that's when setting the `$inject` property
4049          * is very inconvenient. In these situations using the array notation to specify the dependencies in
4050          * a way that survives minification is a better choice:
4051          *
4052          * ```js
4053          *   // We wish to write this (not minification / obfuscation safe)
4054          *   injector.invoke(function($compile, $rootScope) {
4055          *     // ...
4056          *   });
4057          *
4058          *   // We are forced to write break inlining
4059          *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
4060          *     // ...
4061          *   };
4062          *   tmpFn.$inject = ['$compile', '$rootScope'];
4063          *   injector.invoke(tmpFn);
4064          *
4065          *   // To better support inline function the inline annotation is supported
4066          *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
4067          *     // ...
4068          *   }]);
4069          *
4070          *   // Therefore
4071          *   expect(injector.annotate(
4072          *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
4073          *    ).toEqual(['$compile', '$rootScope']);
4074          * ```
4075          *
4076          * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
4077          * be retrieved as described above.
4078          *
4079          * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
4080          *
4081          * @returns {Array.<string>} The names of the services which the function requires.
4082          */
4083
4084
4085
4086
4087         /**
4088          * @ngdoc service
4089          * @name $provide
4090          *
4091          * @description
4092          *
4093          * The {@link auto.$provide $provide} service has a number of methods for registering components
4094          * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
4095          * {@link angular.Module}.
4096          *
4097          * An Angular **service** is a singleton object created by a **service factory**.  These **service
4098          * factories** are functions which, in turn, are created by a **service provider**.
4099          * The **service providers** are constructor functions. When instantiated they must contain a
4100          * property called `$get`, which holds the **service factory** function.
4101          *
4102          * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
4103          * correct **service provider**, instantiating it and then calling its `$get` **service factory**
4104          * function to get the instance of the **service**.
4105          *
4106          * Often services have no configuration options and there is no need to add methods to the service
4107          * provider.  The provider will be no more than a constructor function with a `$get` property. For
4108          * these cases the {@link auto.$provide $provide} service has additional helper methods to register
4109          * services without specifying a provider.
4110          *
4111          * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
4112          *     {@link auto.$injector $injector}
4113          * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
4114          *     providers and services.
4115          * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
4116          *     services, not providers.
4117          * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
4118          *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
4119          *     given factory function.
4120          * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
4121          *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
4122          *      a new object using the given constructor function.
4123          *
4124          * See the individual methods for more information and examples.
4125          */
4126
4127         /**
4128          * @ngdoc method
4129          * @name $provide#provider
4130          * @description
4131          *
4132          * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
4133          * are constructor functions, whose instances are responsible for "providing" a factory for a
4134          * service.
4135          *
4136          * Service provider names start with the name of the service they provide followed by `Provider`.
4137          * For example, the {@link ng.$log $log} service has a provider called
4138          * {@link ng.$logProvider $logProvider}.
4139          *
4140          * Service provider objects can have additional methods which allow configuration of the provider
4141          * and its service. Importantly, you can configure what kind of service is created by the `$get`
4142          * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
4143          * method {@link ng.$logProvider#debugEnabled debugEnabled}
4144          * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
4145          * console or not.
4146          *
4147          * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
4148                                 'Provider'` key.
4149          * @param {(Object|function())} provider If the provider is:
4150          *
4151          *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
4152          *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
4153          *   - `Constructor`: a new instance of the provider will be created using
4154          *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
4155          *
4156          * @returns {Object} registered provider instance
4157
4158          * @example
4159          *
4160          * The following example shows how to create a simple event tracking service and register it using
4161          * {@link auto.$provide#provider $provide.provider()}.
4162          *
4163          * ```js
4164          *  // Define the eventTracker provider
4165          *  function EventTrackerProvider() {
4166          *    var trackingUrl = '/track';
4167          *
4168          *    // A provider method for configuring where the tracked events should been saved
4169          *    this.setTrackingUrl = function(url) {
4170          *      trackingUrl = url;
4171          *    };
4172          *
4173          *    // The service factory function
4174          *    this.$get = ['$http', function($http) {
4175          *      var trackedEvents = {};
4176          *      return {
4177          *        // Call this to track an event
4178          *        event: function(event) {
4179          *          var count = trackedEvents[event] || 0;
4180          *          count += 1;
4181          *          trackedEvents[event] = count;
4182          *          return count;
4183          *        },
4184          *        // Call this to save the tracked events to the trackingUrl
4185          *        save: function() {
4186          *          $http.post(trackingUrl, trackedEvents);
4187          *        }
4188          *      };
4189          *    }];
4190          *  }
4191          *
4192          *  describe('eventTracker', function() {
4193          *    var postSpy;
4194          *
4195          *    beforeEach(module(function($provide) {
4196          *      // Register the eventTracker provider
4197          *      $provide.provider('eventTracker', EventTrackerProvider);
4198          *    }));
4199          *
4200          *    beforeEach(module(function(eventTrackerProvider) {
4201          *      // Configure eventTracker provider
4202          *      eventTrackerProvider.setTrackingUrl('/custom-track');
4203          *    }));
4204          *
4205          *    it('tracks events', inject(function(eventTracker) {
4206          *      expect(eventTracker.event('login')).toEqual(1);
4207          *      expect(eventTracker.event('login')).toEqual(2);
4208          *    }));
4209          *
4210          *    it('saves to the tracking url', inject(function(eventTracker, $http) {
4211          *      postSpy = spyOn($http, 'post');
4212          *      eventTracker.event('login');
4213          *      eventTracker.save();
4214          *      expect(postSpy).toHaveBeenCalled();
4215          *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
4216          *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
4217          *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
4218          *    }));
4219          *  });
4220          * ```
4221          */
4222
4223         /**
4224          * @ngdoc method
4225          * @name $provide#factory
4226          * @description
4227          *
4228          * Register a **service factory**, which will be called to return the service instance.
4229          * This is short for registering a service where its provider consists of only a `$get` property,
4230          * which is the given service factory function.
4231          * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
4232          * configure your service in a provider.
4233          *
4234          * @param {string} name The name of the instance.
4235          * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
4236          *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
4237          * @returns {Object} registered provider instance
4238          *
4239          * @example
4240          * Here is an example of registering a service
4241          * ```js
4242          *   $provide.factory('ping', ['$http', function($http) {
4243          *     return function ping() {
4244          *       return $http.send('/ping');
4245          *     };
4246          *   }]);
4247          * ```
4248          * You would then inject and use this service like this:
4249          * ```js
4250          *   someModule.controller('Ctrl', ['ping', function(ping) {
4251          *     ping();
4252          *   }]);
4253          * ```
4254          */
4255
4256
4257         /**
4258          * @ngdoc method
4259          * @name $provide#service
4260          * @description
4261          *
4262          * Register a **service constructor**, which will be invoked with `new` to create the service
4263          * instance.
4264          * This is short for registering a service where its provider's `$get` property is the service
4265          * constructor function that will be used to instantiate the service instance.
4266          *
4267          * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4268          * as a type/class.
4269          *
4270          * @param {string} name The name of the instance.
4271          * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
4272          *     that will be instantiated.
4273          * @returns {Object} registered provider instance
4274          *
4275          * @example
4276          * Here is an example of registering a service using
4277          * {@link auto.$provide#service $provide.service(class)}.
4278          * ```js
4279          *   var Ping = function($http) {
4280          *     this.$http = $http;
4281          *   };
4282          *
4283          *   Ping.$inject = ['$http'];
4284          *
4285          *   Ping.prototype.send = function() {
4286          *     return this.$http.get('/ping');
4287          *   };
4288          *   $provide.service('ping', Ping);
4289          * ```
4290          * You would then inject and use this service like this:
4291          * ```js
4292          *   someModule.controller('Ctrl', ['ping', function(ping) {
4293          *     ping.send();
4294          *   }]);
4295          * ```
4296          */
4297
4298
4299         /**
4300          * @ngdoc method
4301          * @name $provide#value
4302          * @description
4303          *
4304          * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4305          * number, an array, an object or a function.  This is short for registering a service where its
4306          * provider's `$get` property is a factory function that takes no arguments and returns the **value
4307          * service**.
4308          *
4309          * Value services are similar to constant services, except that they cannot be injected into a
4310          * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4311          * an Angular
4312          * {@link auto.$provide#decorator decorator}.
4313          *
4314          * @param {string} name The name of the instance.
4315          * @param {*} value The value.
4316          * @returns {Object} registered provider instance
4317          *
4318          * @example
4319          * Here are some examples of creating value services.
4320          * ```js
4321          *   $provide.value('ADMIN_USER', 'admin');
4322          *
4323          *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
4324          *
4325          *   $provide.value('halfOf', function(value) {
4326          *     return value / 2;
4327          *   });
4328          * ```
4329          */
4330
4331
4332         /**
4333          * @ngdoc method
4334          * @name $provide#constant
4335          * @description
4336          *
4337          * Register a **constant service**, such as a string, a number, an array, an object or a function,
4338          * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
4339          * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4340          * be overridden by an Angular {@link auto.$provide#decorator decorator}.
4341          *
4342          * @param {string} name The name of the constant.
4343          * @param {*} value The constant value.
4344          * @returns {Object} registered instance
4345          *
4346          * @example
4347          * Here a some examples of creating constants:
4348          * ```js
4349          *   $provide.constant('SHARD_HEIGHT', 306);
4350          *
4351          *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
4352          *
4353          *   $provide.constant('double', function(value) {
4354          *     return value * 2;
4355          *   });
4356          * ```
4357          */
4358
4359
4360         /**
4361          * @ngdoc method
4362          * @name $provide#decorator
4363          * @description
4364          *
4365          * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
4366          * intercepts the creation of a service, allowing it to override or modify the behaviour of the
4367          * service. The object returned by the decorator may be the original service, or a new service
4368          * object which replaces or wraps and delegates to the original service.
4369          *
4370          * @param {string} name The name of the service to decorate.
4371          * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
4372          *    instantiated and should return the decorated service instance. The function is called using
4373          *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
4374          *    Local injection arguments:
4375          *
4376          *    * `$delegate` - The original service instance, which can be monkey patched, configured,
4377          *      decorated or delegated to.
4378          *
4379          * @example
4380          * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4381          * calls to {@link ng.$log#error $log.warn()}.
4382          * ```js
4383          *   $provide.decorator('$log', ['$delegate', function($delegate) {
4384          *     $delegate.warn = $delegate.error;
4385          *     return $delegate;
4386          *   }]);
4387          * ```
4388          */
4389
4390
4391         function createInjector(modulesToLoad, strictDi) {
4392           strictDi = (strictDi === true);
4393           var INSTANTIATING = {},
4394               providerSuffix = 'Provider',
4395               path = [],
4396               loadedModules = new HashMap([], true),
4397               providerCache = {
4398                 $provide: {
4399                     provider: supportObject(provider),
4400                     factory: supportObject(factory),
4401                     service: supportObject(service),
4402                     value: supportObject(value),
4403                     constant: supportObject(constant),
4404                     decorator: decorator
4405                   }
4406               },
4407               providerInjector = (providerCache.$injector =
4408                   createInternalInjector(providerCache, function(serviceName, caller) {
4409                     if (angular.isString(caller)) {
4410                       path.push(caller);
4411                     }
4412                     throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4413                   })),
4414               instanceCache = {},
4415               instanceInjector = (instanceCache.$injector =
4416                   createInternalInjector(instanceCache, function(serviceName, caller) {
4417                     var provider = providerInjector.get(serviceName + providerSuffix, caller);
4418                     return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4419                   }));
4420
4421
4422           forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
4423
4424           return instanceInjector;
4425
4426           ////////////////////////////////////
4427           // $provider
4428           ////////////////////////////////////
4429
4430           function supportObject(delegate) {
4431             return function(key, value) {
4432               if (isObject(key)) {
4433                 forEach(key, reverseParams(delegate));
4434               } else {
4435                 return delegate(key, value);
4436               }
4437             };
4438           }
4439
4440           function provider(name, provider_) {
4441             assertNotHasOwnProperty(name, 'service');
4442             if (isFunction(provider_) || isArray(provider_)) {
4443               provider_ = providerInjector.instantiate(provider_);
4444             }
4445             if (!provider_.$get) {
4446               throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4447             }
4448             return providerCache[name + providerSuffix] = provider_;
4449           }
4450
4451           function enforceReturnValue(name, factory) {
4452             return function enforcedReturnValue() {
4453               var result = instanceInjector.invoke(factory, this);
4454               if (isUndefined(result)) {
4455                 throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4456               }
4457               return result;
4458             };
4459           }
4460
4461           function factory(name, factoryFn, enforce) {
4462             return provider(name, {
4463               $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4464             });
4465           }
4466
4467           function service(name, constructor) {
4468             return factory(name, ['$injector', function($injector) {
4469               return $injector.instantiate(constructor);
4470             }]);
4471           }
4472
4473           function value(name, val) { return factory(name, valueFn(val), false); }
4474
4475           function constant(name, value) {
4476             assertNotHasOwnProperty(name, 'constant');
4477             providerCache[name] = value;
4478             instanceCache[name] = value;
4479           }
4480
4481           function decorator(serviceName, decorFn) {
4482             var origProvider = providerInjector.get(serviceName + providerSuffix),
4483                 orig$get = origProvider.$get;
4484
4485             origProvider.$get = function() {
4486               var origInstance = instanceInjector.invoke(orig$get, origProvider);
4487               return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4488             };
4489           }
4490
4491           ////////////////////////////////////
4492           // Module Loading
4493           ////////////////////////////////////
4494           function loadModules(modulesToLoad) {
4495             assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
4496             var runBlocks = [], moduleFn;
4497             forEach(modulesToLoad, function(module) {
4498               if (loadedModules.get(module)) return;
4499               loadedModules.put(module, true);
4500
4501               function runInvokeQueue(queue) {
4502                 var i, ii;
4503                 for (i = 0, ii = queue.length; i < ii; i++) {
4504                   var invokeArgs = queue[i],
4505                       provider = providerInjector.get(invokeArgs[0]);
4506
4507                   provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4508                 }
4509               }
4510
4511               try {
4512                 if (isString(module)) {
4513                   moduleFn = angularModule(module);
4514                   runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4515                   runInvokeQueue(moduleFn._invokeQueue);
4516                   runInvokeQueue(moduleFn._configBlocks);
4517                 } else if (isFunction(module)) {
4518                     runBlocks.push(providerInjector.invoke(module));
4519                 } else if (isArray(module)) {
4520                     runBlocks.push(providerInjector.invoke(module));
4521                 } else {
4522                   assertArgFn(module, 'module');
4523                 }
4524               } catch (e) {
4525                 if (isArray(module)) {
4526                   module = module[module.length - 1];
4527                 }
4528                 if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4529                   // Safari & FF's stack traces don't contain error.message content
4530                   // unlike those of Chrome and IE
4531                   // So if stack doesn't contain message, we create a new string that contains both.
4532                   // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4533                   /* jshint -W022 */
4534                   e = e.message + '\n' + e.stack;
4535                 }
4536                 throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4537                           module, e.stack || e.message || e);
4538               }
4539             });
4540             return runBlocks;
4541           }
4542
4543           ////////////////////////////////////
4544           // internal Injector
4545           ////////////////////////////////////
4546
4547           function createInternalInjector(cache, factory) {
4548
4549             function getService(serviceName, caller) {
4550               if (cache.hasOwnProperty(serviceName)) {
4551                 if (cache[serviceName] === INSTANTIATING) {
4552                   throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4553                             serviceName + ' <- ' + path.join(' <- '));
4554                 }
4555                 return cache[serviceName];
4556               } else {
4557                 try {
4558                   path.unshift(serviceName);
4559                   cache[serviceName] = INSTANTIATING;
4560                   return cache[serviceName] = factory(serviceName, caller);
4561                 } catch (err) {
4562                   if (cache[serviceName] === INSTANTIATING) {
4563                     delete cache[serviceName];
4564                   }
4565                   throw err;
4566                 } finally {
4567                   path.shift();
4568                 }
4569               }
4570             }
4571
4572             function invoke(fn, self, locals, serviceName) {
4573               if (typeof locals === 'string') {
4574                 serviceName = locals;
4575                 locals = null;
4576               }
4577
4578               var args = [],
4579                   $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4580                   length, i,
4581                   key;
4582
4583               for (i = 0, length = $inject.length; i < length; i++) {
4584                 key = $inject[i];
4585                 if (typeof key !== 'string') {
4586                   throw $injectorMinErr('itkn',
4587                           'Incorrect injection token! Expected service name as string, got {0}', key);
4588                 }
4589                 args.push(
4590                   locals && locals.hasOwnProperty(key)
4591                   ? locals[key]
4592                   : getService(key, serviceName)
4593                 );
4594               }
4595               if (isArray(fn)) {
4596                 fn = fn[length];
4597               }
4598
4599               // http://jsperf.com/angularjs-invoke-apply-vs-switch
4600               // #5388
4601               return fn.apply(self, args);
4602             }
4603
4604             function instantiate(Type, locals, serviceName) {
4605               // Check if Type is annotated and use just the given function at n-1 as parameter
4606               // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4607               // Object creation: http://jsperf.com/create-constructor/2
4608               var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4609               var returnedValue = invoke(Type, instance, locals, serviceName);
4610
4611               return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4612             }
4613
4614             return {
4615               invoke: invoke,
4616               instantiate: instantiate,
4617               get: getService,
4618               annotate: createInjector.$$annotate,
4619               has: function(name) {
4620                 return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4621               }
4622             };
4623           }
4624         }
4625
4626         createInjector.$$annotate = annotate;
4627
4628         /**
4629          * @ngdoc provider
4630          * @name $anchorScrollProvider
4631          *
4632          * @description
4633          * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4634          * {@link ng.$location#hash $location.hash()} changes.
4635          */
4636         function $AnchorScrollProvider() {
4637
4638           var autoScrollingEnabled = true;
4639
4640           /**
4641            * @ngdoc method
4642            * @name $anchorScrollProvider#disableAutoScrolling
4643            *
4644            * @description
4645            * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4646            * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4647            * Use this method to disable automatic scrolling.
4648            *
4649            * If automatic scrolling is disabled, one must explicitly call
4650            * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4651            * current hash.
4652            */
4653           this.disableAutoScrolling = function() {
4654             autoScrollingEnabled = false;
4655           };
4656
4657           /**
4658            * @ngdoc service
4659            * @name $anchorScroll
4660            * @kind function
4661            * @requires $window
4662            * @requires $location
4663            * @requires $rootScope
4664            *
4665            * @description
4666            * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
4667            * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
4668            * in the
4669            * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
4670            *
4671            * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4672            * match any anchor whenever it changes. This can be disabled by calling
4673            * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4674            *
4675            * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4676            * vertical scroll-offset (either fixed or dynamic).
4677            *
4678            * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
4679            *                       {@link ng.$location#hash $location.hash()} will be used.
4680            *
4681            * @property {(number|function|jqLite)} yOffset
4682            * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4683            * positioned elements at the top of the page, such as navbars, headers etc.
4684            *
4685            * `yOffset` can be specified in various ways:
4686            * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4687            * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4688            *   a number representing the offset (in pixels).<br /><br />
4689            * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4690            *   the top of the page to the element's bottom will be used as offset.<br />
4691            *   **Note**: The element will be taken into account only as long as its `position` is set to
4692            *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4693            *   their height and/or positioning according to the viewport's size.
4694            *
4695            * <br />
4696            * <div class="alert alert-warning">
4697            * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4698            * not some child element.
4699            * </div>
4700            *
4701            * @example
4702              <example module="anchorScrollExample">
4703                <file name="index.html">
4704                  <div id="scrollArea" ng-controller="ScrollController">
4705                    <a ng-click="gotoBottom()">Go to bottom</a>
4706                    <a id="bottom"></a> You're at the bottom!
4707                  </div>
4708                </file>
4709                <file name="script.js">
4710                  angular.module('anchorScrollExample', [])
4711                    .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4712                      function ($scope, $location, $anchorScroll) {
4713                        $scope.gotoBottom = function() {
4714                          // set the location.hash to the id of
4715                          // the element you wish to scroll to.
4716                          $location.hash('bottom');
4717
4718                          // call $anchorScroll()
4719                          $anchorScroll();
4720                        };
4721                      }]);
4722                </file>
4723                <file name="style.css">
4724                  #scrollArea {
4725                    height: 280px;
4726                    overflow: auto;
4727                  }
4728
4729                  #bottom {
4730                    display: block;
4731                    margin-top: 2000px;
4732                  }
4733                </file>
4734              </example>
4735            *
4736            * <hr />
4737            * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4738            * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4739            *
4740            * @example
4741              <example module="anchorScrollOffsetExample">
4742                <file name="index.html">
4743                  <div class="fixed-header" ng-controller="headerCtrl">
4744                    <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4745                      Go to anchor {{x}}
4746                    </a>
4747                  </div>
4748                  <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4749                    Anchor {{x}} of 5
4750                  </div>
4751                </file>
4752                <file name="script.js">
4753                  angular.module('anchorScrollOffsetExample', [])
4754                    .run(['$anchorScroll', function($anchorScroll) {
4755                      $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4756                    }])
4757                    .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4758                      function ($anchorScroll, $location, $scope) {
4759                        $scope.gotoAnchor = function(x) {
4760                          var newHash = 'anchor' + x;
4761                          if ($location.hash() !== newHash) {
4762                            // set the $location.hash to `newHash` and
4763                            // $anchorScroll will automatically scroll to it
4764                            $location.hash('anchor' + x);
4765                          } else {
4766                            // call $anchorScroll() explicitly,
4767                            // since $location.hash hasn't changed
4768                            $anchorScroll();
4769                          }
4770                        };
4771                      }
4772                    ]);
4773                </file>
4774                <file name="style.css">
4775                  body {
4776                    padding-top: 50px;
4777                  }
4778
4779                  .anchor {
4780                    border: 2px dashed DarkOrchid;
4781                    padding: 10px 10px 200px 10px;
4782                  }
4783
4784                  .fixed-header {
4785                    background-color: rgba(0, 0, 0, 0.2);
4786                    height: 50px;
4787                    position: fixed;
4788                    top: 0; left: 0; right: 0;
4789                  }
4790
4791                  .fixed-header > a {
4792                    display: inline-block;
4793                    margin: 5px 15px;
4794                  }
4795                </file>
4796              </example>
4797            */
4798           this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4799             var document = $window.document;
4800
4801             // Helper function to get first anchor from a NodeList
4802             // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4803             //  and working in all supported browsers.)
4804             function getFirstAnchor(list) {
4805               var result = null;
4806               Array.prototype.some.call(list, function(element) {
4807                 if (nodeName_(element) === 'a') {
4808                   result = element;
4809                   return true;
4810                 }
4811               });
4812               return result;
4813             }
4814
4815             function getYOffset() {
4816
4817               var offset = scroll.yOffset;
4818
4819               if (isFunction(offset)) {
4820                 offset = offset();
4821               } else if (isElement(offset)) {
4822                 var elem = offset[0];
4823                 var style = $window.getComputedStyle(elem);
4824                 if (style.position !== 'fixed') {
4825                   offset = 0;
4826                 } else {
4827                   offset = elem.getBoundingClientRect().bottom;
4828                 }
4829               } else if (!isNumber(offset)) {
4830                 offset = 0;
4831               }
4832
4833               return offset;
4834             }
4835
4836             function scrollTo(elem) {
4837               if (elem) {
4838                 elem.scrollIntoView();
4839
4840                 var offset = getYOffset();
4841
4842                 if (offset) {
4843                   // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4844                   // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4845                   // top of the viewport.
4846                   //
4847                   // IF the number of pixels from the top of `elem` to the end of the page's content is less
4848                   // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4849                   // way down the page.
4850                   //
4851                   // This is often the case for elements near the bottom of the page.
4852                   //
4853                   // In such cases we do not need to scroll the whole `offset` up, just the difference between
4854                   // the top of the element and the offset, which is enough to align the top of `elem` at the
4855                   // desired position.
4856                   var elemTop = elem.getBoundingClientRect().top;
4857                   $window.scrollBy(0, elemTop - offset);
4858                 }
4859               } else {
4860                 $window.scrollTo(0, 0);
4861               }
4862             }
4863
4864             function scroll(hash) {
4865               hash = isString(hash) ? hash : $location.hash();
4866               var elm;
4867
4868               // empty hash, scroll to the top of the page
4869               if (!hash) scrollTo(null);
4870
4871               // element with given id
4872               else if ((elm = document.getElementById(hash))) scrollTo(elm);
4873
4874               // first anchor with given name :-D
4875               else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4876
4877               // no element and hash == 'top', scroll to the top of the page
4878               else if (hash === 'top') scrollTo(null);
4879             }
4880
4881             // does not scroll when user clicks on anchor link that is currently on
4882             // (no url change, no $location.hash() change), browser native does scroll
4883             if (autoScrollingEnabled) {
4884               $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4885                 function autoScrollWatchAction(newVal, oldVal) {
4886                   // skip the initial scroll if $location.hash is empty
4887                   if (newVal === oldVal && newVal === '') return;
4888
4889                   jqLiteDocumentLoaded(function() {
4890                     $rootScope.$evalAsync(scroll);
4891                   });
4892                 });
4893             }
4894
4895             return scroll;
4896           }];
4897         }
4898
4899         var $animateMinErr = minErr('$animate');
4900         var ELEMENT_NODE = 1;
4901         var NG_ANIMATE_CLASSNAME = 'ng-animate';
4902
4903         function mergeClasses(a,b) {
4904           if (!a && !b) return '';
4905           if (!a) return b;
4906           if (!b) return a;
4907           if (isArray(a)) a = a.join(' ');
4908           if (isArray(b)) b = b.join(' ');
4909           return a + ' ' + b;
4910         }
4911
4912         function extractElementNode(element) {
4913           for (var i = 0; i < element.length; i++) {
4914             var elm = element[i];
4915             if (elm.nodeType === ELEMENT_NODE) {
4916               return elm;
4917             }
4918           }
4919         }
4920
4921         function splitClasses(classes) {
4922           if (isString(classes)) {
4923             classes = classes.split(' ');
4924           }
4925
4926           // Use createMap() to prevent class assumptions involving property names in
4927           // Object.prototype
4928           var obj = createMap();
4929           forEach(classes, function(klass) {
4930             // sometimes the split leaves empty string values
4931             // incase extra spaces were applied to the options
4932             if (klass.length) {
4933               obj[klass] = true;
4934             }
4935           });
4936           return obj;
4937         }
4938
4939         // if any other type of options value besides an Object value is
4940         // passed into the $animate.method() animation then this helper code
4941         // will be run which will ignore it. While this patch is not the
4942         // greatest solution to this, a lot of existing plugins depend on
4943         // $animate to either call the callback (< 1.2) or return a promise
4944         // that can be changed. This helper function ensures that the options
4945         // are wiped clean incase a callback function is provided.
4946         function prepareAnimateOptions(options) {
4947           return isObject(options)
4948               ? options
4949               : {};
4950         }
4951
4952         var $$CoreAnimateRunnerProvider = function() {
4953           this.$get = ['$q', '$$rAF', function($q, $$rAF) {
4954             function AnimateRunner() {}
4955             AnimateRunner.all = noop;
4956             AnimateRunner.chain = noop;
4957             AnimateRunner.prototype = {
4958               end: noop,
4959               cancel: noop,
4960               resume: noop,
4961               pause: noop,
4962               complete: noop,
4963               then: function(pass, fail) {
4964                 return $q(function(resolve) {
4965                   $$rAF(function() {
4966                     resolve();
4967                   });
4968                 }).then(pass, fail);
4969               }
4970             };
4971             return AnimateRunner;
4972           }];
4973         };
4974
4975         // this is prefixed with Core since it conflicts with
4976         // the animateQueueProvider defined in ngAnimate/animateQueue.js
4977         var $$CoreAnimateQueueProvider = function() {
4978           var postDigestQueue = new HashMap();
4979           var postDigestElements = [];
4980
4981           this.$get = ['$$AnimateRunner', '$rootScope',
4982                function($$AnimateRunner,   $rootScope) {
4983             return {
4984               enabled: noop,
4985               on: noop,
4986               off: noop,
4987               pin: noop,
4988
4989               push: function(element, event, options, domOperation) {
4990                 domOperation        && domOperation();
4991
4992                 options = options || {};
4993                 options.from        && element.css(options.from);
4994                 options.to          && element.css(options.to);
4995
4996                 if (options.addClass || options.removeClass) {
4997                   addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
4998                 }
4999
5000                 return new $$AnimateRunner(); // jshint ignore:line
5001               }
5002             };
5003
5004
5005             function updateData(data, classes, value) {
5006               var changed = false;
5007               if (classes) {
5008                 classes = isString(classes) ? classes.split(' ') :
5009                           isArray(classes) ? classes : [];
5010                 forEach(classes, function(className) {
5011                   if (className) {
5012                     changed = true;
5013                     data[className] = value;
5014                   }
5015                 });
5016               }
5017               return changed;
5018             }
5019
5020             function handleCSSClassChanges() {
5021               forEach(postDigestElements, function(element) {
5022                 var data = postDigestQueue.get(element);
5023                 if (data) {
5024                   var existing = splitClasses(element.attr('class'));
5025                   var toAdd = '';
5026                   var toRemove = '';
5027                   forEach(data, function(status, className) {
5028                     var hasClass = !!existing[className];
5029                     if (status !== hasClass) {
5030                       if (status) {
5031                         toAdd += (toAdd.length ? ' ' : '') + className;
5032                       } else {
5033                         toRemove += (toRemove.length ? ' ' : '') + className;
5034                       }
5035                     }
5036                   });
5037
5038                   forEach(element, function(elm) {
5039                     toAdd    && jqLiteAddClass(elm, toAdd);
5040                     toRemove && jqLiteRemoveClass(elm, toRemove);
5041                   });
5042                   postDigestQueue.remove(element);
5043                 }
5044               });
5045               postDigestElements.length = 0;
5046             }
5047
5048
5049             function addRemoveClassesPostDigest(element, add, remove) {
5050               var data = postDigestQueue.get(element) || {};
5051
5052               var classesAdded = updateData(data, add, true);
5053               var classesRemoved = updateData(data, remove, false);
5054
5055               if (classesAdded || classesRemoved) {
5056
5057                 postDigestQueue.put(element, data);
5058                 postDigestElements.push(element);
5059
5060                 if (postDigestElements.length === 1) {
5061                   $rootScope.$$postDigest(handleCSSClassChanges);
5062                 }
5063               }
5064             }
5065           }];
5066         };
5067
5068         /**
5069          * @ngdoc provider
5070          * @name $animateProvider
5071          *
5072          * @description
5073          * Default implementation of $animate that doesn't perform any animations, instead just
5074          * synchronously performs DOM updates and resolves the returned runner promise.
5075          *
5076          * In order to enable animations the `ngAnimate` module has to be loaded.
5077          *
5078          * To see the functional implementation check out `src/ngAnimate/animate.js`.
5079          */
5080         var $AnimateProvider = ['$provide', function($provide) {
5081           var provider = this;
5082
5083           this.$$registeredAnimations = Object.create(null);
5084
5085            /**
5086            * @ngdoc method
5087            * @name $animateProvider#register
5088            *
5089            * @description
5090            * Registers a new injectable animation factory function. The factory function produces the
5091            * animation object which contains callback functions for each event that is expected to be
5092            * animated.
5093            *
5094            *   * `eventFn`: `function(element, ... , doneFunction, options)`
5095            *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
5096            *   on the type of animation additional arguments will be injected into the animation function. The
5097            *   list below explains the function signatures for the different animation methods:
5098            *
5099            *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
5100            *   - addClass: function(element, addedClasses, doneFunction, options)
5101            *   - removeClass: function(element, removedClasses, doneFunction, options)
5102            *   - enter, leave, move: function(element, doneFunction, options)
5103            *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
5104            *
5105            *   Make sure to trigger the `doneFunction` once the animation is fully complete.
5106            *
5107            * ```js
5108            *   return {
5109            *     //enter, leave, move signature
5110            *     eventFn : function(element, done, options) {
5111            *       //code to run the animation
5112            *       //once complete, then run done()
5113            *       return function endFunction(wasCancelled) {
5114            *         //code to cancel the animation
5115            *       }
5116            *     }
5117            *   }
5118            * ```
5119            *
5120            * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
5121            * @param {Function} factory The factory function that will be executed to return the animation
5122            *                           object.
5123            */
5124           this.register = function(name, factory) {
5125             if (name && name.charAt(0) !== '.') {
5126               throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
5127             }
5128
5129             var key = name + '-animation';
5130             provider.$$registeredAnimations[name.substr(1)] = key;
5131             $provide.factory(key, factory);
5132           };
5133
5134           /**
5135            * @ngdoc method
5136            * @name $animateProvider#classNameFilter
5137            *
5138            * @description
5139            * Sets and/or returns the CSS class regular expression that is checked when performing
5140            * an animation. Upon bootstrap the classNameFilter value is not set at all and will
5141            * therefore enable $animate to attempt to perform an animation on any element that is triggered.
5142            * When setting the `classNameFilter` value, animations will only be performed on elements
5143            * that successfully match the filter expression. This in turn can boost performance
5144            * for low-powered devices as well as applications containing a lot of structural operations.
5145            * @param {RegExp=} expression The className expression which will be checked against all animations
5146            * @return {RegExp} The current CSS className expression value. If null then there is no expression value
5147            */
5148           this.classNameFilter = function(expression) {
5149             if (arguments.length === 1) {
5150               this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
5151               if (this.$$classNameFilter) {
5152                 var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
5153                 if (reservedRegex.test(this.$$classNameFilter.toString())) {
5154                   throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
5155
5156                 }
5157               }
5158             }
5159             return this.$$classNameFilter;
5160           };
5161
5162           this.$get = ['$$animateQueue', function($$animateQueue) {
5163             function domInsert(element, parentElement, afterElement) {
5164               // if for some reason the previous element was removed
5165               // from the dom sometime before this code runs then let's
5166               // just stick to using the parent element as the anchor
5167               if (afterElement) {
5168                 var afterNode = extractElementNode(afterElement);
5169                 if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
5170                   afterElement = null;
5171                 }
5172               }
5173               afterElement ? afterElement.after(element) : parentElement.prepend(element);
5174             }
5175
5176             /**
5177              * @ngdoc service
5178              * @name $animate
5179              * @description The $animate service exposes a series of DOM utility methods that provide support
5180              * for animation hooks. The default behavior is the application of DOM operations, however,
5181              * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
5182              * to ensure that animation runs with the triggered DOM operation.
5183              *
5184              * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
5185              * included and only when it is active then the animation hooks that `$animate` triggers will be
5186              * functional. Once active then all structural `ng-` directives will trigger animations as they perform
5187              * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
5188              * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
5189              *
5190              * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
5191              *
5192              * To learn more about enabling animation support, click here to visit the
5193              * {@link ngAnimate ngAnimate module page}.
5194              */
5195             return {
5196               // we don't call it directly since non-existant arguments may
5197               // be interpreted as null within the sub enabled function
5198
5199               /**
5200                *
5201                * @ngdoc method
5202                * @name $animate#on
5203                * @kind function
5204                * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
5205                *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
5206                *    is fired with the following params:
5207                *
5208                * ```js
5209                * $animate.on('enter', container,
5210                *    function callback(element, phase) {
5211                *      // cool we detected an enter animation within the container
5212                *    }
5213                * );
5214                * ```
5215                *
5216                * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
5217                * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
5218                *     as well as among its children
5219                * @param {Function} callback the callback function that will be fired when the listener is triggered
5220                *
5221                * The arguments present in the callback function are:
5222                * * `element` - The captured DOM element that the animation was fired on.
5223                * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
5224                */
5225               on: $$animateQueue.on,
5226
5227               /**
5228                *
5229                * @ngdoc method
5230                * @name $animate#off
5231                * @kind function
5232                * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
5233                * can be used in three different ways depending on the arguments:
5234                *
5235                * ```js
5236                * // remove all the animation event listeners listening for `enter`
5237                * $animate.off('enter');
5238                *
5239                * // remove all the animation event listeners listening for `enter` on the given element and its children
5240                * $animate.off('enter', container);
5241                *
5242                * // remove the event listener function provided by `listenerFn` that is set
5243                * // to listen for `enter` on the given `element` as well as its children
5244                * $animate.off('enter', container, callback);
5245                * ```
5246                *
5247                * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
5248                * @param {DOMElement=} container the container element the event listener was placed on
5249                * @param {Function=} callback the callback function that was registered as the listener
5250                */
5251               off: $$animateQueue.off,
5252
5253               /**
5254                * @ngdoc method
5255                * @name $animate#pin
5256                * @kind function
5257                * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
5258                *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
5259                *    element despite being outside the realm of the application or within another application. Say for example if the application
5260                *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
5261                *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
5262                *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
5263                *
5264                *    Note that this feature is only active when the `ngAnimate` module is used.
5265                *
5266                * @param {DOMElement} element the external element that will be pinned
5267                * @param {DOMElement} parentElement the host parent element that will be associated with the external element
5268                */
5269               pin: $$animateQueue.pin,
5270
5271               /**
5272                *
5273                * @ngdoc method
5274                * @name $animate#enabled
5275                * @kind function
5276                * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
5277                * function can be called in four ways:
5278                *
5279                * ```js
5280                * // returns true or false
5281                * $animate.enabled();
5282                *
5283                * // changes the enabled state for all animations
5284                * $animate.enabled(false);
5285                * $animate.enabled(true);
5286                *
5287                * // returns true or false if animations are enabled for an element
5288                * $animate.enabled(element);
5289                *
5290                * // changes the enabled state for an element and its children
5291                * $animate.enabled(element, true);
5292                * $animate.enabled(element, false);
5293                * ```
5294                *
5295                * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
5296                * @param {boolean=} enabled whether or not the animations will be enabled for the element
5297                *
5298                * @return {boolean} whether or not animations are enabled
5299                */
5300               enabled: $$animateQueue.enabled,
5301
5302               /**
5303                * @ngdoc method
5304                * @name $animate#cancel
5305                * @kind function
5306                * @description Cancels the provided animation.
5307                *
5308                * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
5309                */
5310               cancel: function(runner) {
5311                 runner.end && runner.end();
5312               },
5313
5314               /**
5315                *
5316                * @ngdoc method
5317                * @name $animate#enter
5318                * @kind function
5319                * @description Inserts the element into the DOM either after the `after` element (if provided) or
5320                *   as the first child within the `parent` element and then triggers an animation.
5321                *   A promise is returned that will be resolved during the next digest once the animation
5322                *   has completed.
5323                *
5324                * @param {DOMElement} element the element which will be inserted into the DOM
5325                * @param {DOMElement} parent the parent element which will append the element as
5326                *   a child (so long as the after element is not present)
5327                * @param {DOMElement=} after the sibling element after which the element will be appended
5328                * @param {object=} options an optional collection of options/styles that will be applied to the element
5329                *
5330                * @return {Promise} the animation callback promise
5331                */
5332               enter: function(element, parent, after, options) {
5333                 parent = parent && jqLite(parent);
5334                 after = after && jqLite(after);
5335                 parent = parent || after.parent();
5336                 domInsert(element, parent, after);
5337                 return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
5338               },
5339
5340               /**
5341                *
5342                * @ngdoc method
5343                * @name $animate#move
5344                * @kind function
5345                * @description Inserts (moves) the element into its new position in the DOM either after
5346                *   the `after` element (if provided) or as the first child within the `parent` element
5347                *   and then triggers an animation. A promise is returned that will be resolved
5348                *   during the next digest once the animation has completed.
5349                *
5350                * @param {DOMElement} element the element which will be moved into the new DOM position
5351                * @param {DOMElement} parent the parent element which will append the element as
5352                *   a child (so long as the after element is not present)
5353                * @param {DOMElement=} after the sibling element after which the element will be appended
5354                * @param {object=} options an optional collection of options/styles that will be applied to the element
5355                *
5356                * @return {Promise} the animation callback promise
5357                */
5358               move: function(element, parent, after, options) {
5359                 parent = parent && jqLite(parent);
5360                 after = after && jqLite(after);
5361                 parent = parent || after.parent();
5362                 domInsert(element, parent, after);
5363                 return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
5364               },
5365
5366               /**
5367                * @ngdoc method
5368                * @name $animate#leave
5369                * @kind function
5370                * @description Triggers an animation and then removes the element from the DOM.
5371                * When the function is called a promise is returned that will be resolved during the next
5372                * digest once the animation has completed.
5373                *
5374                * @param {DOMElement} element the element which will be removed from the DOM
5375                * @param {object=} options an optional collection of options/styles that will be applied to the element
5376                *
5377                * @return {Promise} the animation callback promise
5378                */
5379               leave: function(element, options) {
5380                 return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
5381                   element.remove();
5382                 });
5383               },
5384
5385               /**
5386                * @ngdoc method
5387                * @name $animate#addClass
5388                * @kind function
5389                *
5390                * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
5391                *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
5392                *   animation if element already contains the CSS class or if the class is removed at a later step.
5393                *   Note that class-based animations are treated differently compared to structural animations
5394                *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5395                *   depending if CSS or JavaScript animations are used.
5396                *
5397                * @param {DOMElement} element the element which the CSS classes will be applied to
5398                * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
5399                * @param {object=} options an optional collection of options/styles that will be applied to the element
5400                *
5401                * @return {Promise} the animation callback promise
5402                */
5403               addClass: function(element, className, options) {
5404                 options = prepareAnimateOptions(options);
5405                 options.addClass = mergeClasses(options.addclass, className);
5406                 return $$animateQueue.push(element, 'addClass', options);
5407               },
5408
5409               /**
5410                * @ngdoc method
5411                * @name $animate#removeClass
5412                * @kind function
5413                *
5414                * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
5415                *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
5416                *   animation if element does not contain the CSS class or if the class is added at a later step.
5417                *   Note that class-based animations are treated differently compared to structural animations
5418                *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5419                *   depending if CSS or JavaScript animations are used.
5420                *
5421                * @param {DOMElement} element the element which the CSS classes will be applied to
5422                * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
5423                * @param {object=} options an optional collection of options/styles that will be applied to the element
5424                *
5425                * @return {Promise} the animation callback promise
5426                */
5427               removeClass: function(element, className, options) {
5428                 options = prepareAnimateOptions(options);
5429                 options.removeClass = mergeClasses(options.removeClass, className);
5430                 return $$animateQueue.push(element, 'removeClass', options);
5431               },
5432
5433               /**
5434                * @ngdoc method
5435                * @name $animate#setClass
5436                * @kind function
5437                *
5438                * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
5439                *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
5440                *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
5441                *    passed. Note that class-based animations are treated differently compared to structural animations
5442                *    (like enter, move and leave) since the CSS classes may be added/removed at different points
5443                *    depending if CSS or JavaScript animations are used.
5444                *
5445                * @param {DOMElement} element the element which the CSS classes will be applied to
5446                * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
5447                * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
5448                * @param {object=} options an optional collection of options/styles that will be applied to the element
5449                *
5450                * @return {Promise} the animation callback promise
5451                */
5452               setClass: function(element, add, remove, options) {
5453                 options = prepareAnimateOptions(options);
5454                 options.addClass = mergeClasses(options.addClass, add);
5455                 options.removeClass = mergeClasses(options.removeClass, remove);
5456                 return $$animateQueue.push(element, 'setClass', options);
5457               },
5458
5459               /**
5460                * @ngdoc method
5461                * @name $animate#animate
5462                * @kind function
5463                *
5464                * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
5465                * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
5466                * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
5467                * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
5468                * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
5469                *
5470                * @param {DOMElement} element the element which the CSS styles will be applied to
5471                * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
5472                * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
5473                * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
5474                *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
5475                *    (Note that if no animation is detected then this value will not be appplied to the element.)
5476                * @param {object=} options an optional collection of options/styles that will be applied to the element
5477                *
5478                * @return {Promise} the animation callback promise
5479                */
5480               animate: function(element, from, to, className, options) {
5481                 options = prepareAnimateOptions(options);
5482                 options.from = options.from ? extend(options.from, from) : from;
5483                 options.to   = options.to   ? extend(options.to, to)     : to;
5484
5485                 className = className || 'ng-inline-animate';
5486                 options.tempClasses = mergeClasses(options.tempClasses, className);
5487                 return $$animateQueue.push(element, 'animate', options);
5488               }
5489             };
5490           }];
5491         }];
5492
5493         /**
5494          * @ngdoc service
5495          * @name $animateCss
5496          * @kind object
5497          *
5498          * @description
5499          * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
5500          * then the `$animateCss` service will actually perform animations.
5501          *
5502          * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
5503          */
5504         var $CoreAnimateCssProvider = function() {
5505           this.$get = ['$$rAF', '$q', function($$rAF, $q) {
5506
5507             var RAFPromise = function() {};
5508             RAFPromise.prototype = {
5509               done: function(cancel) {
5510                 this.defer && this.defer[cancel === true ? 'reject' : 'resolve']();
5511               },
5512               end: function() {
5513                 this.done();
5514               },
5515               cancel: function() {
5516                 this.done(true);
5517               },
5518               getPromise: function() {
5519                 if (!this.defer) {
5520                   this.defer = $q.defer();
5521                 }
5522                 return this.defer.promise;
5523               },
5524               then: function(f1,f2) {
5525                 return this.getPromise().then(f1,f2);
5526               },
5527               'catch': function(f1) {
5528                 return this.getPromise()['catch'](f1);
5529               },
5530               'finally': function(f1) {
5531                 return this.getPromise()['finally'](f1);
5532               }
5533             };
5534
5535             return function(element, options) {
5536               // there is no point in applying the styles since
5537               // there is no animation that goes on at all in
5538               // this version of $animateCss.
5539               if (options.cleanupStyles) {
5540                 options.from = options.to = null;
5541               }
5542
5543               if (options.from) {
5544                 element.css(options.from);
5545                 options.from = null;
5546               }
5547
5548               var closed, runner = new RAFPromise();
5549               return {
5550                 start: run,
5551                 end: run
5552               };
5553
5554               function run() {
5555                 $$rAF(function() {
5556                   close();
5557                   if (!closed) {
5558                     runner.done();
5559                   }
5560                   closed = true;
5561                 });
5562                 return runner;
5563               }
5564
5565               function close() {
5566                 if (options.addClass) {
5567                   element.addClass(options.addClass);
5568                   options.addClass = null;
5569                 }
5570                 if (options.removeClass) {
5571                   element.removeClass(options.removeClass);
5572                   options.removeClass = null;
5573                 }
5574                 if (options.to) {
5575                   element.css(options.to);
5576                   options.to = null;
5577                 }
5578               }
5579             };
5580           }];
5581         };
5582
5583         /* global stripHash: true */
5584
5585         /**
5586          * ! This is a private undocumented service !
5587          *
5588          * @name $browser
5589          * @requires $log
5590          * @description
5591          * This object has two goals:
5592          *
5593          * - hide all the global state in the browser caused by the window object
5594          * - abstract away all the browser specific features and inconsistencies
5595          *
5596          * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
5597          * service, which can be used for convenient testing of the application without the interaction with
5598          * the real browser apis.
5599          */
5600         /**
5601          * @param {object} window The global window object.
5602          * @param {object} document jQuery wrapped document.
5603          * @param {object} $log window.console or an object with the same interface.
5604          * @param {object} $sniffer $sniffer service
5605          */
5606         function Browser(window, document, $log, $sniffer) {
5607           var self = this,
5608               rawDocument = document[0],
5609               location = window.location,
5610               history = window.history,
5611               setTimeout = window.setTimeout,
5612               clearTimeout = window.clearTimeout,
5613               pendingDeferIds = {};
5614
5615           self.isMock = false;
5616
5617           var outstandingRequestCount = 0;
5618           var outstandingRequestCallbacks = [];
5619
5620           // TODO(vojta): remove this temporary api
5621           self.$$completeOutstandingRequest = completeOutstandingRequest;
5622           self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
5623
5624           /**
5625            * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
5626            * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
5627            */
5628           function completeOutstandingRequest(fn) {
5629             try {
5630               fn.apply(null, sliceArgs(arguments, 1));
5631             } finally {
5632               outstandingRequestCount--;
5633               if (outstandingRequestCount === 0) {
5634                 while (outstandingRequestCallbacks.length) {
5635                   try {
5636                     outstandingRequestCallbacks.pop()();
5637                   } catch (e) {
5638                     $log.error(e);
5639                   }
5640                 }
5641               }
5642             }
5643           }
5644
5645           function getHash(url) {
5646             var index = url.indexOf('#');
5647             return index === -1 ? '' : url.substr(index);
5648           }
5649
5650           /**
5651            * @private
5652            * Note: this method is used only by scenario runner
5653            * TODO(vojta): prefix this method with $$ ?
5654            * @param {function()} callback Function that will be called when no outstanding request
5655            */
5656           self.notifyWhenNoOutstandingRequests = function(callback) {
5657             if (outstandingRequestCount === 0) {
5658               callback();
5659             } else {
5660               outstandingRequestCallbacks.push(callback);
5661             }
5662           };
5663
5664           //////////////////////////////////////////////////////////////
5665           // URL API
5666           //////////////////////////////////////////////////////////////
5667
5668           var cachedState, lastHistoryState,
5669               lastBrowserUrl = location.href,
5670               baseElement = document.find('base'),
5671               pendingLocation = null;
5672
5673           cacheState();
5674           lastHistoryState = cachedState;
5675
5676           /**
5677            * @name $browser#url
5678            *
5679            * @description
5680            * GETTER:
5681            * Without any argument, this method just returns current value of location.href.
5682            *
5683            * SETTER:
5684            * With at least one argument, this method sets url to new value.
5685            * If html5 history api supported, pushState/replaceState is used, otherwise
5686            * location.href/location.replace is used.
5687            * Returns its own instance to allow chaining
5688            *
5689            * NOTE: this api is intended for use only by the $location service. Please use the
5690            * {@link ng.$location $location service} to change url.
5691            *
5692            * @param {string} url New url (when used as setter)
5693            * @param {boolean=} replace Should new url replace current history record?
5694            * @param {object=} state object to use with pushState/replaceState
5695            */
5696           self.url = function(url, replace, state) {
5697             // In modern browsers `history.state` is `null` by default; treating it separately
5698             // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
5699             // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
5700             if (isUndefined(state)) {
5701               state = null;
5702             }
5703
5704             // Android Browser BFCache causes location, history reference to become stale.
5705             if (location !== window.location) location = window.location;
5706             if (history !== window.history) history = window.history;
5707
5708             // setter
5709             if (url) {
5710               var sameState = lastHistoryState === state;
5711
5712               // Don't change anything if previous and current URLs and states match. This also prevents
5713               // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
5714               // See https://github.com/angular/angular.js/commit/ffb2701
5715               if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
5716                 return self;
5717               }
5718               var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
5719               lastBrowserUrl = url;
5720               lastHistoryState = state;
5721               // Don't use history API if only the hash changed
5722               // due to a bug in IE10/IE11 which leads
5723               // to not firing a `hashchange` nor `popstate` event
5724               // in some cases (see #9143).
5725               if ($sniffer.history && (!sameBase || !sameState)) {
5726                 history[replace ? 'replaceState' : 'pushState'](state, '', url);
5727                 cacheState();
5728                 // Do the assignment again so that those two variables are referentially identical.
5729                 lastHistoryState = cachedState;
5730               } else {
5731                 if (!sameBase || pendingLocation) {
5732                   pendingLocation = url;
5733                 }
5734                 if (replace) {
5735                   location.replace(url);
5736                 } else if (!sameBase) {
5737                   location.href = url;
5738                 } else {
5739                   location.hash = getHash(url);
5740                 }
5741                 if (location.href !== url) {
5742                   pendingLocation = url;
5743                 }
5744               }
5745               return self;
5746             // getter
5747             } else {
5748               // - pendingLocation is needed as browsers don't allow to read out
5749               //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
5750               //   https://openradar.appspot.com/22186109).
5751               // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
5752               return pendingLocation || location.href.replace(/%27/g,"'");
5753             }
5754           };
5755
5756           /**
5757            * @name $browser#state
5758            *
5759            * @description
5760            * This method is a getter.
5761            *
5762            * Return history.state or null if history.state is undefined.
5763            *
5764            * @returns {object} state
5765            */
5766           self.state = function() {
5767             return cachedState;
5768           };
5769
5770           var urlChangeListeners = [],
5771               urlChangeInit = false;
5772
5773           function cacheStateAndFireUrlChange() {
5774             pendingLocation = null;
5775             cacheState();
5776             fireUrlChange();
5777           }
5778
5779           function getCurrentState() {
5780             try {
5781               return history.state;
5782             } catch (e) {
5783               // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5784             }
5785           }
5786
5787           // This variable should be used *only* inside the cacheState function.
5788           var lastCachedState = null;
5789           function cacheState() {
5790             // This should be the only place in $browser where `history.state` is read.
5791             cachedState = getCurrentState();
5792             cachedState = isUndefined(cachedState) ? null : cachedState;
5793
5794             // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5795             if (equals(cachedState, lastCachedState)) {
5796               cachedState = lastCachedState;
5797             }
5798             lastCachedState = cachedState;
5799           }
5800
5801           function fireUrlChange() {
5802             if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
5803               return;
5804             }
5805
5806             lastBrowserUrl = self.url();
5807             lastHistoryState = cachedState;
5808             forEach(urlChangeListeners, function(listener) {
5809               listener(self.url(), cachedState);
5810             });
5811           }
5812
5813           /**
5814            * @name $browser#onUrlChange
5815            *
5816            * @description
5817            * Register callback function that will be called, when url changes.
5818            *
5819            * It's only called when the url is changed from outside of angular:
5820            * - user types different url into address bar
5821            * - user clicks on history (forward/back) button
5822            * - user clicks on a link
5823            *
5824            * It's not called when url is changed by $browser.url() method
5825            *
5826            * The listener gets called with new url as parameter.
5827            *
5828            * NOTE: this api is intended for use only by the $location service. Please use the
5829            * {@link ng.$location $location service} to monitor url changes in angular apps.
5830            *
5831            * @param {function(string)} listener Listener function to be called when url changes.
5832            * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
5833            */
5834           self.onUrlChange = function(callback) {
5835             // TODO(vojta): refactor to use node's syntax for events
5836             if (!urlChangeInit) {
5837               // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
5838               // don't fire popstate when user change the address bar and don't fire hashchange when url
5839               // changed by push/replaceState
5840
5841               // html5 history api - popstate event
5842               if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
5843               // hashchange event
5844               jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
5845
5846               urlChangeInit = true;
5847             }
5848
5849             urlChangeListeners.push(callback);
5850             return callback;
5851           };
5852
5853           /**
5854            * @private
5855            * Remove popstate and hashchange handler from window.
5856            *
5857            * NOTE: this api is intended for use only by $rootScope.
5858            */
5859           self.$$applicationDestroyed = function() {
5860             jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
5861           };
5862
5863           /**
5864            * Checks whether the url has changed outside of Angular.
5865            * Needs to be exported to be able to check for changes that have been done in sync,
5866            * as hashchange/popstate events fire in async.
5867            */
5868           self.$$checkUrlChange = fireUrlChange;
5869
5870           //////////////////////////////////////////////////////////////
5871           // Misc API
5872           //////////////////////////////////////////////////////////////
5873
5874           /**
5875            * @name $browser#baseHref
5876            *
5877            * @description
5878            * Returns current <base href>
5879            * (always relative - without domain)
5880            *
5881            * @returns {string} The current base href
5882            */
5883           self.baseHref = function() {
5884             var href = baseElement.attr('href');
5885             return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
5886           };
5887
5888           /**
5889            * @name $browser#defer
5890            * @param {function()} fn A function, who's execution should be deferred.
5891            * @param {number=} [delay=0] of milliseconds to defer the function execution.
5892            * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
5893            *
5894            * @description
5895            * Executes a fn asynchronously via `setTimeout(fn, delay)`.
5896            *
5897            * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
5898            * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
5899            * via `$browser.defer.flush()`.
5900            *
5901            */
5902           self.defer = function(fn, delay) {
5903             var timeoutId;
5904             outstandingRequestCount++;
5905             timeoutId = setTimeout(function() {
5906               delete pendingDeferIds[timeoutId];
5907               completeOutstandingRequest(fn);
5908             }, delay || 0);
5909             pendingDeferIds[timeoutId] = true;
5910             return timeoutId;
5911           };
5912
5913
5914           /**
5915            * @name $browser#defer.cancel
5916            *
5917            * @description
5918            * Cancels a deferred task identified with `deferId`.
5919            *
5920            * @param {*} deferId Token returned by the `$browser.defer` function.
5921            * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
5922            *                    canceled.
5923            */
5924           self.defer.cancel = function(deferId) {
5925             if (pendingDeferIds[deferId]) {
5926               delete pendingDeferIds[deferId];
5927               clearTimeout(deferId);
5928               completeOutstandingRequest(noop);
5929               return true;
5930             }
5931             return false;
5932           };
5933
5934         }
5935
5936         function $BrowserProvider() {
5937           this.$get = ['$window', '$log', '$sniffer', '$document',
5938               function($window, $log, $sniffer, $document) {
5939                 return new Browser($window, $document, $log, $sniffer);
5940               }];
5941         }
5942
5943         /**
5944          * @ngdoc service
5945          * @name $cacheFactory
5946          *
5947          * @description
5948          * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
5949          * them.
5950          *
5951          * ```js
5952          *
5953          *  var cache = $cacheFactory('cacheId');
5954          *  expect($cacheFactory.get('cacheId')).toBe(cache);
5955          *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
5956          *
5957          *  cache.put("key", "value");
5958          *  cache.put("another key", "another value");
5959          *
5960          *  // We've specified no options on creation
5961          *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
5962          *
5963          * ```
5964          *
5965          *
5966          * @param {string} cacheId Name or id of the newly created cache.
5967          * @param {object=} options Options object that specifies the cache behavior. Properties:
5968          *
5969          *   - `{number=}` `capacity` — turns the cache into LRU cache.
5970          *
5971          * @returns {object} Newly created cache object with the following set of methods:
5972          *
5973          * - `{object}` `info()` — Returns id, size, and options of cache.
5974          * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
5975          *   it.
5976          * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
5977          * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
5978          * - `{void}` `removeAll()` — Removes all cached values.
5979          * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
5980          *
5981          * @example
5982            <example module="cacheExampleApp">
5983              <file name="index.html">
5984                <div ng-controller="CacheController">
5985                  <input ng-model="newCacheKey" placeholder="Key">
5986                  <input ng-model="newCacheValue" placeholder="Value">
5987                  <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
5988
5989                  <p ng-if="keys.length">Cached Values</p>
5990                  <div ng-repeat="key in keys">
5991                    <span ng-bind="key"></span>
5992                    <span>: </span>
5993                    <b ng-bind="cache.get(key)"></b>
5994                  </div>
5995
5996                  <p>Cache Info</p>
5997                  <div ng-repeat="(key, value) in cache.info()">
5998                    <span ng-bind="key"></span>
5999                    <span>: </span>
6000                    <b ng-bind="value"></b>
6001                  </div>
6002                </div>
6003              </file>
6004              <file name="script.js">
6005                angular.module('cacheExampleApp', []).
6006                  controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
6007                    $scope.keys = [];
6008                    $scope.cache = $cacheFactory('cacheId');
6009                    $scope.put = function(key, value) {
6010                      if (angular.isUndefined($scope.cache.get(key))) {
6011                        $scope.keys.push(key);
6012                      }
6013                      $scope.cache.put(key, angular.isUndefined(value) ? null : value);
6014                    };
6015                  }]);
6016              </file>
6017              <file name="style.css">
6018                p {
6019                  margin: 10px 0 3px;
6020                }
6021              </file>
6022            </example>
6023          */
6024         function $CacheFactoryProvider() {
6025
6026           this.$get = function() {
6027             var caches = {};
6028
6029             function cacheFactory(cacheId, options) {
6030               if (cacheId in caches) {
6031                 throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
6032               }
6033
6034               var size = 0,
6035                   stats = extend({}, options, {id: cacheId}),
6036                   data = createMap(),
6037                   capacity = (options && options.capacity) || Number.MAX_VALUE,
6038                   lruHash = createMap(),
6039                   freshEnd = null,
6040                   staleEnd = null;
6041
6042               /**
6043                * @ngdoc type
6044                * @name $cacheFactory.Cache
6045                *
6046                * @description
6047                * A cache object used to store and retrieve data, primarily used by
6048                * {@link $http $http} and the {@link ng.directive:script script} directive to cache
6049                * templates and other data.
6050                *
6051                * ```js
6052                *  angular.module('superCache')
6053                *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
6054                *      return $cacheFactory('super-cache');
6055                *    }]);
6056                * ```
6057                *
6058                * Example test:
6059                *
6060                * ```js
6061                *  it('should behave like a cache', inject(function(superCache) {
6062                *    superCache.put('key', 'value');
6063                *    superCache.put('another key', 'another value');
6064                *
6065                *    expect(superCache.info()).toEqual({
6066                *      id: 'super-cache',
6067                *      size: 2
6068                *    });
6069                *
6070                *    superCache.remove('another key');
6071                *    expect(superCache.get('another key')).toBeUndefined();
6072                *
6073                *    superCache.removeAll();
6074                *    expect(superCache.info()).toEqual({
6075                *      id: 'super-cache',
6076                *      size: 0
6077                *    });
6078                *  }));
6079                * ```
6080                */
6081               return caches[cacheId] = {
6082
6083                 /**
6084                  * @ngdoc method
6085                  * @name $cacheFactory.Cache#put
6086                  * @kind function
6087                  *
6088                  * @description
6089                  * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
6090                  * retrieved later, and incrementing the size of the cache if the key was not already
6091                  * present in the cache. If behaving like an LRU cache, it will also remove stale
6092                  * entries from the set.
6093                  *
6094                  * It will not insert undefined values into the cache.
6095                  *
6096                  * @param {string} key the key under which the cached data is stored.
6097                  * @param {*} value the value to store alongside the key. If it is undefined, the key
6098                  *    will not be stored.
6099                  * @returns {*} the value stored.
6100                  */
6101                 put: function(key, value) {
6102                   if (isUndefined(value)) return;
6103                   if (capacity < Number.MAX_VALUE) {
6104                     var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
6105
6106                     refresh(lruEntry);
6107                   }
6108
6109                   if (!(key in data)) size++;
6110                   data[key] = value;
6111
6112                   if (size > capacity) {
6113                     this.remove(staleEnd.key);
6114                   }
6115
6116                   return value;
6117                 },
6118
6119                 /**
6120                  * @ngdoc method
6121                  * @name $cacheFactory.Cache#get
6122                  * @kind function
6123                  *
6124                  * @description
6125                  * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
6126                  *
6127                  * @param {string} key the key of the data to be retrieved
6128                  * @returns {*} the value stored.
6129                  */
6130                 get: function(key) {
6131                   if (capacity < Number.MAX_VALUE) {
6132                     var lruEntry = lruHash[key];
6133
6134                     if (!lruEntry) return;
6135
6136                     refresh(lruEntry);
6137                   }
6138
6139                   return data[key];
6140                 },
6141
6142
6143                 /**
6144                  * @ngdoc method
6145                  * @name $cacheFactory.Cache#remove
6146                  * @kind function
6147                  *
6148                  * @description
6149                  * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
6150                  *
6151                  * @param {string} key the key of the entry to be removed
6152                  */
6153                 remove: function(key) {
6154                   if (capacity < Number.MAX_VALUE) {
6155                     var lruEntry = lruHash[key];
6156
6157                     if (!lruEntry) return;
6158
6159                     if (lruEntry == freshEnd) freshEnd = lruEntry.p;
6160                     if (lruEntry == staleEnd) staleEnd = lruEntry.n;
6161                     link(lruEntry.n,lruEntry.p);
6162
6163                     delete lruHash[key];
6164                   }
6165
6166                   if (!(key in data)) return;
6167
6168                   delete data[key];
6169                   size--;
6170                 },
6171
6172
6173                 /**
6174                  * @ngdoc method
6175                  * @name $cacheFactory.Cache#removeAll
6176                  * @kind function
6177                  *
6178                  * @description
6179                  * Clears the cache object of any entries.
6180                  */
6181                 removeAll: function() {
6182                   data = createMap();
6183                   size = 0;
6184                   lruHash = createMap();
6185                   freshEnd = staleEnd = null;
6186                 },
6187
6188
6189                 /**
6190                  * @ngdoc method
6191                  * @name $cacheFactory.Cache#destroy
6192                  * @kind function
6193                  *
6194                  * @description
6195                  * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
6196                  * removing it from the {@link $cacheFactory $cacheFactory} set.
6197                  */
6198                 destroy: function() {
6199                   data = null;
6200                   stats = null;
6201                   lruHash = null;
6202                   delete caches[cacheId];
6203                 },
6204
6205
6206                 /**
6207                  * @ngdoc method
6208                  * @name $cacheFactory.Cache#info
6209                  * @kind function
6210                  *
6211                  * @description
6212                  * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
6213                  *
6214                  * @returns {object} an object with the following properties:
6215                  *   <ul>
6216                  *     <li>**id**: the id of the cache instance</li>
6217                  *     <li>**size**: the number of entries kept in the cache instance</li>
6218                  *     <li>**...**: any additional properties from the options object when creating the
6219                  *       cache.</li>
6220                  *   </ul>
6221                  */
6222                 info: function() {
6223                   return extend({}, stats, {size: size});
6224                 }
6225               };
6226
6227
6228               /**
6229                * makes the `entry` the freshEnd of the LRU linked list
6230                */
6231               function refresh(entry) {
6232                 if (entry != freshEnd) {
6233                   if (!staleEnd) {
6234                     staleEnd = entry;
6235                   } else if (staleEnd == entry) {
6236                     staleEnd = entry.n;
6237                   }
6238
6239                   link(entry.n, entry.p);
6240                   link(entry, freshEnd);
6241                   freshEnd = entry;
6242                   freshEnd.n = null;
6243                 }
6244               }
6245
6246
6247               /**
6248                * bidirectionally links two entries of the LRU linked list
6249                */
6250               function link(nextEntry, prevEntry) {
6251                 if (nextEntry != prevEntry) {
6252                   if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
6253                   if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
6254                 }
6255               }
6256             }
6257
6258
6259           /**
6260            * @ngdoc method
6261            * @name $cacheFactory#info
6262            *
6263            * @description
6264            * Get information about all the caches that have been created
6265            *
6266            * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
6267            */
6268             cacheFactory.info = function() {
6269               var info = {};
6270               forEach(caches, function(cache, cacheId) {
6271                 info[cacheId] = cache.info();
6272               });
6273               return info;
6274             };
6275
6276
6277           /**
6278            * @ngdoc method
6279            * @name $cacheFactory#get
6280            *
6281            * @description
6282            * Get access to a cache object by the `cacheId` used when it was created.
6283            *
6284            * @param {string} cacheId Name or id of a cache to access.
6285            * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
6286            */
6287             cacheFactory.get = function(cacheId) {
6288               return caches[cacheId];
6289             };
6290
6291
6292             return cacheFactory;
6293           };
6294         }
6295
6296         /**
6297          * @ngdoc service
6298          * @name $templateCache
6299          *
6300          * @description
6301          * The first time a template is used, it is loaded in the template cache for quick retrieval. You
6302          * can load templates directly into the cache in a `script` tag, or by consuming the
6303          * `$templateCache` service directly.
6304          *
6305          * Adding via the `script` tag:
6306          *
6307          * ```html
6308          *   <script type="text/ng-template" id="templateId.html">
6309          *     <p>This is the content of the template</p>
6310          *   </script>
6311          * ```
6312          *
6313          * **Note:** the `script` tag containing the template does not need to be included in the `head` of
6314          * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
6315          * element with ng-app attribute), otherwise the template will be ignored.
6316          *
6317          * Adding via the `$templateCache` service:
6318          *
6319          * ```js
6320          * var myApp = angular.module('myApp', []);
6321          * myApp.run(function($templateCache) {
6322          *   $templateCache.put('templateId.html', 'This is the content of the template');
6323          * });
6324          * ```
6325          *
6326          * To retrieve the template later, simply use it in your HTML:
6327          * ```html
6328          * <div ng-include=" 'templateId.html' "></div>
6329          * ```
6330          *
6331          * or get it via Javascript:
6332          * ```js
6333          * $templateCache.get('templateId.html')
6334          * ```
6335          *
6336          * See {@link ng.$cacheFactory $cacheFactory}.
6337          *
6338          */
6339         function $TemplateCacheProvider() {
6340           this.$get = ['$cacheFactory', function($cacheFactory) {
6341             return $cacheFactory('templates');
6342           }];
6343         }
6344
6345         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6346          *     Any commits to this file should be reviewed with security in mind.  *
6347          *   Changes to this file can potentially create security vulnerabilities. *
6348          *          An approval from 2 Core members with history of modifying      *
6349          *                         this file is required.                          *
6350          *                                                                         *
6351          *  Does the change somehow allow for arbitrary javascript to be executed? *
6352          *    Or allows for someone to change the prototype of built-in objects?   *
6353          *     Or gives undesired access to variables likes document or window?    *
6354          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6355
6356         /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
6357          *
6358          * DOM-related variables:
6359          *
6360          * - "node" - DOM Node
6361          * - "element" - DOM Element or Node
6362          * - "$node" or "$element" - jqLite-wrapped node or element
6363          *
6364          *
6365          * Compiler related stuff:
6366          *
6367          * - "linkFn" - linking fn of a single directive
6368          * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
6369          * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
6370          * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
6371          */
6372
6373
6374         /**
6375          * @ngdoc service
6376          * @name $compile
6377          * @kind function
6378          *
6379          * @description
6380          * Compiles an HTML string or DOM into a template and produces a template function, which
6381          * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
6382          *
6383          * The compilation is a process of walking the DOM tree and matching DOM elements to
6384          * {@link ng.$compileProvider#directive directives}.
6385          *
6386          * <div class="alert alert-warning">
6387          * **Note:** This document is an in-depth reference of all directive options.
6388          * For a gentle introduction to directives with examples of common use cases,
6389          * see the {@link guide/directive directive guide}.
6390          * </div>
6391          *
6392          * ## Comprehensive Directive API
6393          *
6394          * There are many different options for a directive.
6395          *
6396          * The difference resides in the return value of the factory function.
6397          * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
6398          * or just the `postLink` function (all other properties will have the default values).
6399          *
6400          * <div class="alert alert-success">
6401          * **Best Practice:** It's recommended to use the "directive definition object" form.
6402          * </div>
6403          *
6404          * Here's an example directive declared with a Directive Definition Object:
6405          *
6406          * ```js
6407          *   var myModule = angular.module(...);
6408          *
6409          *   myModule.directive('directiveName', function factory(injectables) {
6410          *     var directiveDefinitionObject = {
6411          *       priority: 0,
6412          *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
6413          *       // or
6414          *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
6415          *       transclude: false,
6416          *       restrict: 'A',
6417          *       templateNamespace: 'html',
6418          *       scope: false,
6419          *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
6420          *       controllerAs: 'stringIdentifier',
6421          *       bindToController: false,
6422          *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
6423          *       compile: function compile(tElement, tAttrs, transclude) {
6424          *         return {
6425          *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6426          *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
6427          *         }
6428          *         // or
6429          *         // return function postLink( ... ) { ... }
6430          *       },
6431          *       // or
6432          *       // link: {
6433          *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6434          *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
6435          *       // }
6436          *       // or
6437          *       // link: function postLink( ... ) { ... }
6438          *     };
6439          *     return directiveDefinitionObject;
6440          *   });
6441          * ```
6442          *
6443          * <div class="alert alert-warning">
6444          * **Note:** Any unspecified options will use the default value. You can see the default values below.
6445          * </div>
6446          *
6447          * Therefore the above can be simplified as:
6448          *
6449          * ```js
6450          *   var myModule = angular.module(...);
6451          *
6452          *   myModule.directive('directiveName', function factory(injectables) {
6453          *     var directiveDefinitionObject = {
6454          *       link: function postLink(scope, iElement, iAttrs) { ... }
6455          *     };
6456          *     return directiveDefinitionObject;
6457          *     // or
6458          *     // return function postLink(scope, iElement, iAttrs) { ... }
6459          *   });
6460          * ```
6461          *
6462          *
6463          *
6464          * ### Directive Definition Object
6465          *
6466          * The directive definition object provides instructions to the {@link ng.$compile
6467          * compiler}. The attributes are:
6468          *
6469          * #### `multiElement`
6470          * When this property is set to true, the HTML compiler will collect DOM nodes between
6471          * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
6472          * together as the directive elements. It is recommended that this feature be used on directives
6473          * which are not strictly behavioural (such as {@link ngClick}), and which
6474          * do not manipulate or replace child nodes (such as {@link ngInclude}).
6475          *
6476          * #### `priority`
6477          * When there are multiple directives defined on a single DOM element, sometimes it
6478          * is necessary to specify the order in which the directives are applied. The `priority` is used
6479          * to sort the directives before their `compile` functions get called. Priority is defined as a
6480          * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
6481          * are also run in priority order, but post-link functions are run in reverse order. The order
6482          * of directives with the same priority is undefined. The default priority is `0`.
6483          *
6484          * #### `terminal`
6485          * If set to true then the current `priority` will be the last set of directives
6486          * which will execute (any directives at the current priority will still execute
6487          * as the order of execution on same `priority` is undefined). Note that expressions
6488          * and other directives used in the directive's template will also be excluded from execution.
6489          *
6490          * #### `scope`
6491          * The scope property can be `true`, an object or a falsy value:
6492          *
6493          * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
6494          *
6495          * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
6496          * the directive's element. If multiple directives on the same element request a new scope,
6497          * only one new scope is created. The new scope rule does not apply for the root of the template
6498          * since the root of the template always gets a new scope.
6499          *
6500          * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
6501          * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
6502          * scope. This is useful when creating reusable components, which should not accidentally read or modify
6503          * data in the parent scope.
6504          *
6505          * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
6506          * directive's element. These local properties are useful for aliasing values for templates. The keys in
6507          * the object hash map to the name of the property on the isolate scope; the values define how the property
6508          * is bound to the parent scope, via matching attributes on the directive's element:
6509          *
6510          * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
6511          *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
6512          *   attribute name is assumed to be the same as the local name.
6513          *   Given `<widget my-attr="hello {{name}}">` and widget definition
6514          *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
6515          *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
6516          *   `localName` property on the widget scope. The `name` is read from the parent scope (not
6517          *   component scope).
6518          *
6519          * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
6520          *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
6521          *   name is specified then the attribute name is assumed to be the same as the local name.
6522          *   Given `<widget my-attr="parentModel">` and widget definition of
6523          *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
6524          *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
6525          *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
6526          *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
6527          *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
6528          *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
6529          *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
6530          *
6531          * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
6532          *   If no `attr` name is specified then the attribute name is assumed to be the same as the
6533          *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
6534          *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
6535          *   a function wrapper for the `count = count + value` expression. Often it's desirable to
6536          *   pass data from the isolated scope via an expression to the parent scope, this can be
6537          *   done by passing a map of local variable names and values into the expression wrapper fn.
6538          *   For example, if the expression is `increment(amount)` then we can specify the amount value
6539          *   by calling the `localFn` as `localFn({amount: 22})`.
6540          *
6541          * In general it's possible to apply more than one directive to one element, but there might be limitations
6542          * depending on the type of scope required by the directives. The following points will help explain these limitations.
6543          * For simplicity only two directives are taken into account, but it is also applicable for several directives:
6544          *
6545          * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
6546          * * **child scope** + **no scope** =>  Both directives will share one single child scope
6547          * * **child scope** + **child scope** =>  Both directives will share one single child scope
6548          * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
6549          * its parent's scope
6550          * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
6551          * be applied to the same element.
6552          * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
6553          * cannot be applied to the same element.
6554          *
6555          *
6556          * #### `bindToController`
6557          * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
6558          * allow a component to have its properties bound to the controller, rather than to scope. When the controller
6559          * is instantiated, the initial values of the isolate scope bindings are already available.
6560          *
6561          * #### `controller`
6562          * Controller constructor function. The controller is instantiated before the
6563          * pre-linking phase and can be accessed by other directives (see
6564          * `require` attribute). This allows the directives to communicate with each other and augment
6565          * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
6566          *
6567          * * `$scope` - Current scope associated with the element
6568          * * `$element` - Current element
6569          * * `$attrs` - Current attributes object for the element
6570          * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
6571          *   `function([scope], cloneLinkingFn, futureParentElement)`.
6572          *    * `scope`: optional argument to override the scope.
6573          *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
6574          *    * `futureParentElement`:
6575          *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
6576          *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
6577          *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
6578          *          and when the `cloneLinkinFn` is passed,
6579          *          as those elements need to created and cloned in a special way when they are defined outside their
6580          *          usual containers (e.g. like `<svg>`).
6581          *        * See also the `directive.templateNamespace` property.
6582          *
6583          *
6584          * #### `require`
6585          * Require another directive and inject its controller as the fourth argument to the linking function. The
6586          * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
6587          * injected argument will be an array in corresponding order. If no such directive can be
6588          * found, or if the directive does not have a controller, then an error is raised (unless no link function
6589          * is specified, in which case error checking is skipped). The name can be prefixed with:
6590          *
6591          * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
6592          * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
6593          * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
6594          * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
6595          * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
6596          *   `null` to the `link` fn if not found.
6597          * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
6598          *   `null` to the `link` fn if not found.
6599          *
6600          *
6601          * #### `controllerAs`
6602          * Identifier name for a reference to the controller in the directive's scope.
6603          * This allows the controller to be referenced from the directive template. This is especially
6604          * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
6605          * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
6606          * `controllerAs` reference might overwrite a property that already exists on the parent scope.
6607          *
6608          *
6609          * #### `restrict`
6610          * String of subset of `EACM` which restricts the directive to a specific directive
6611          * declaration style. If omitted, the defaults (elements and attributes) are used.
6612          *
6613          * * `E` - Element name (default): `<my-directive></my-directive>`
6614          * * `A` - Attribute (default): `<div my-directive="exp"></div>`
6615          * * `C` - Class: `<div class="my-directive: exp;"></div>`
6616          * * `M` - Comment: `<!-- directive: my-directive exp -->`
6617          *
6618          *
6619          * #### `templateNamespace`
6620          * String representing the document type used by the markup in the template.
6621          * AngularJS needs this information as those elements need to be created and cloned
6622          * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
6623          *
6624          * * `html` - All root nodes in the template are HTML. Root nodes may also be
6625          *   top-level elements such as `<svg>` or `<math>`.
6626          * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
6627          * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
6628          *
6629          * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
6630          *
6631          * #### `template`
6632          * HTML markup that may:
6633          * * Replace the contents of the directive's element (default).
6634          * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
6635          * * Wrap the contents of the directive's element (if `transclude` is true).
6636          *
6637          * Value may be:
6638          *
6639          * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
6640          * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
6641          *   function api below) and returns a string value.
6642          *
6643          *
6644          * #### `templateUrl`
6645          * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
6646          *
6647          * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
6648          * for later when the template has been resolved.  In the meantime it will continue to compile and link
6649          * sibling and parent elements as though this element had not contained any directives.
6650          *
6651          * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
6652          * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
6653          * case when only one deeply nested directive has `templateUrl`.
6654          *
6655          * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
6656          *
6657          * You can specify `templateUrl` as a string representing the URL or as a function which takes two
6658          * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
6659          * a string value representing the url.  In either case, the template URL is passed through {@link
6660          * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
6661          *
6662          *
6663          * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
6664          * specify what the template should replace. Defaults to `false`.
6665          *
6666          * * `true` - the template will replace the directive's element.
6667          * * `false` - the template will replace the contents of the directive's element.
6668          *
6669          * The replacement process migrates all of the attributes / classes from the old element to the new
6670          * one. See the {@link guide/directive#template-expanding-directive
6671          * Directives Guide} for an example.
6672          *
6673          * There are very few scenarios where element replacement is required for the application function,
6674          * the main one being reusable custom components that are used within SVG contexts
6675          * (because SVG doesn't work with custom elements in the DOM tree).
6676          *
6677          * #### `transclude`
6678          * Extract the contents of the element where the directive appears and make it available to the directive.
6679          * The contents are compiled and provided to the directive as a **transclusion function**. See the
6680          * {@link $compile#transclusion Transclusion} section below.
6681          *
6682          * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6683          * directive's element or the entire element:
6684          *
6685          * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6686          * * `'element'` - transclude the whole of the directive's element including any directives on this
6687          *   element that defined at a lower priority than this directive. When used, the `template`
6688          *   property is ignored.
6689          *
6690          *
6691          * #### `compile`
6692          *
6693          * ```js
6694          *   function compile(tElement, tAttrs, transclude) { ... }
6695          * ```
6696          *
6697          * The compile function deals with transforming the template DOM. Since most directives do not do
6698          * template transformation, it is not used often. The compile function takes the following arguments:
6699          *
6700          *   * `tElement` - template element - The element where the directive has been declared. It is
6701          *     safe to do template transformation on the element and child elements only.
6702          *
6703          *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
6704          *     between all directive compile functions.
6705          *
6706          *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
6707          *
6708          * <div class="alert alert-warning">
6709          * **Note:** The template instance and the link instance may be different objects if the template has
6710          * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
6711          * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
6712          * should be done in a linking function rather than in a compile function.
6713          * </div>
6714
6715          * <div class="alert alert-warning">
6716          * **Note:** The compile function cannot handle directives that recursively use themselves in their
6717          * own templates or compile functions. Compiling these directives results in an infinite loop and a
6718          * stack overflow errors.
6719          *
6720          * This can be avoided by manually using $compile in the postLink function to imperatively compile
6721          * a directive's template instead of relying on automatic template compilation via `template` or
6722          * `templateUrl` declaration or manual compilation inside the compile function.
6723          * </div>
6724          *
6725          * <div class="alert alert-danger">
6726          * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
6727          *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
6728          *   to the link function instead.
6729          * </div>
6730
6731          * A compile function can have a return value which can be either a function or an object.
6732          *
6733          * * returning a (post-link) function - is equivalent to registering the linking function via the
6734          *   `link` property of the config object when the compile function is empty.
6735          *
6736          * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
6737          *   control when a linking function should be called during the linking phase. See info about
6738          *   pre-linking and post-linking functions below.
6739          *
6740          *
6741          * #### `link`
6742          * This property is used only if the `compile` property is not defined.
6743          *
6744          * ```js
6745          *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
6746          * ```
6747          *
6748          * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
6749          * executed after the template has been cloned. This is where most of the directive logic will be
6750          * put.
6751          *
6752          *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
6753          *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
6754          *
6755          *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
6756          *     manipulate the children of the element only in `postLink` function since the children have
6757          *     already been linked.
6758          *
6759          *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
6760          *     between all directive linking functions.
6761          *
6762          *   * `controller` - the directive's required controller instance(s) - Instances are shared
6763          *     among all directives, which allows the directives to use the controllers as a communication
6764          *     channel. The exact value depends on the directive's `require` property:
6765          *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
6766          *       * `string`: the controller instance
6767          *       * `array`: array of controller instances
6768          *
6769          *     If a required controller cannot be found, and it is optional, the instance is `null`,
6770          *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
6771          *
6772          *     Note that you can also require the directive's own controller - it will be made available like
6773          *     any other controller.
6774          *
6775          *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
6776          *     This is the same as the `$transclude`
6777          *     parameter of directive controllers, see there for details.
6778          *     `function([scope], cloneLinkingFn, futureParentElement)`.
6779          *
6780          * #### Pre-linking function
6781          *
6782          * Executed before the child elements are linked. Not safe to do DOM transformation since the
6783          * compiler linking function will fail to locate the correct elements for linking.
6784          *
6785          * #### Post-linking function
6786          *
6787          * Executed after the child elements are linked.
6788          *
6789          * Note that child elements that contain `templateUrl` directives will not have been compiled
6790          * and linked since they are waiting for their template to load asynchronously and their own
6791          * compilation and linking has been suspended until that occurs.
6792          *
6793          * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
6794          * for their async templates to be resolved.
6795          *
6796          *
6797          * ### Transclusion
6798          *
6799          * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
6800          * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
6801          * scope from where they were taken.
6802          *
6803          * Transclusion is used (often with {@link ngTransclude}) to insert the
6804          * original contents of a directive's element into a specified place in the template of the directive.
6805          * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
6806          * content has access to the properties on the scope from which it was taken, even if the directive
6807          * has isolated scope.
6808          * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
6809          *
6810          * This makes it possible for the widget to have private state for its template, while the transcluded
6811          * content has access to its originating scope.
6812          *
6813          * <div class="alert alert-warning">
6814          * **Note:** When testing an element transclude directive you must not place the directive at the root of the
6815          * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
6816          * Testing Transclusion Directives}.
6817          * </div>
6818          *
6819          * #### Transclusion Functions
6820          *
6821          * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
6822          * function** to the directive's `link` function and `controller`. This transclusion function is a special
6823          * **linking function** that will return the compiled contents linked to a new transclusion scope.
6824          *
6825          * <div class="alert alert-info">
6826          * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
6827          * ngTransclude will deal with it for us.
6828          * </div>
6829          *
6830          * If you want to manually control the insertion and removal of the transcluded content in your directive
6831          * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
6832          * object that contains the compiled DOM, which is linked to the correct transclusion scope.
6833          *
6834          * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
6835          * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
6836          * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6837          *
6838          * <div class="alert alert-info">
6839          * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
6840          * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6841          * </div>
6842          *
6843          * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
6844          * attach function**:
6845          *
6846          * ```js
6847          * var transcludedContent, transclusionScope;
6848          *
6849          * $transclude(function(clone, scope) {
6850          *   element.append(clone);
6851          *   transcludedContent = clone;
6852          *   transclusionScope = scope;
6853          * });
6854          * ```
6855          *
6856          * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
6857          * associated transclusion scope:
6858          *
6859          * ```js
6860          * transcludedContent.remove();
6861          * transclusionScope.$destroy();
6862          * ```
6863          *
6864          * <div class="alert alert-info">
6865          * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
6866          * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
6867          * then you are also responsible for calling `$destroy` on the transclusion scope.
6868          * </div>
6869          *
6870          * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6871          * automatically destroy their transluded clones as necessary so you do not need to worry about this if
6872          * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6873          *
6874          *
6875          * #### Transclusion Scopes
6876          *
6877          * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
6878          * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
6879          * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
6880          * was taken.
6881          *
6882          * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
6883          * like this:
6884          *
6885          * ```html
6886          * <div ng-app>
6887          *   <div isolate>
6888          *     <div transclusion>
6889          *     </div>
6890          *   </div>
6891          * </div>
6892          * ```
6893          *
6894          * The `$parent` scope hierarchy will look like this:
6895          *
6896          * ```
6897          * - $rootScope
6898          *   - isolate
6899          *     - transclusion
6900          * ```
6901          *
6902          * but the scopes will inherit prototypically from different scopes to their `$parent`.
6903          *
6904          * ```
6905          * - $rootScope
6906          *   - transclusion
6907          * - isolate
6908          * ```
6909          *
6910          *
6911          * ### Attributes
6912          *
6913          * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6914          * `link()` or `compile()` functions. It has a variety of uses.
6915          *
6916          * accessing *Normalized attribute names:*
6917          * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6918          * the attributes object allows for normalized access to
6919          *   the attributes.
6920          *
6921          * * *Directive inter-communication:* All directives share the same instance of the attributes
6922          *   object which allows the directives to use the attributes object as inter directive
6923          *   communication.
6924          *
6925          * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
6926          *   allowing other directives to read the interpolated value.
6927          *
6928          * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
6929          *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
6930          *   the only way to easily get the actual value because during the linking phase the interpolation
6931          *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
6932          *
6933          * ```js
6934          * function linkingFn(scope, elm, attrs, ctrl) {
6935          *   // get the attribute value
6936          *   console.log(attrs.ngModel);
6937          *
6938          *   // change the attribute
6939          *   attrs.$set('ngModel', 'new value');
6940          *
6941          *   // observe changes to interpolated attribute
6942          *   attrs.$observe('ngModel', function(value) {
6943          *     console.log('ngModel has changed value to ' + value);
6944          *   });
6945          * }
6946          * ```
6947          *
6948          * ## Example
6949          *
6950          * <div class="alert alert-warning">
6951          * **Note**: Typically directives are registered with `module.directive`. The example below is
6952          * to illustrate how `$compile` works.
6953          * </div>
6954          *
6955          <example module="compileExample">
6956            <file name="index.html">
6957             <script>
6958               angular.module('compileExample', [], function($compileProvider) {
6959                 // configure new 'compile' directive by passing a directive
6960                 // factory function. The factory function injects the '$compile'
6961                 $compileProvider.directive('compile', function($compile) {
6962                   // directive factory creates a link function
6963                   return function(scope, element, attrs) {
6964                     scope.$watch(
6965                       function(scope) {
6966                          // watch the 'compile' expression for changes
6967                         return scope.$eval(attrs.compile);
6968                       },
6969                       function(value) {
6970                         // when the 'compile' expression changes
6971                         // assign it into the current DOM
6972                         element.html(value);
6973
6974                         // compile the new DOM and link it to the current
6975                         // scope.
6976                         // NOTE: we only compile .childNodes so that
6977                         // we don't get into infinite loop compiling ourselves
6978                         $compile(element.contents())(scope);
6979                       }
6980                     );
6981                   };
6982                 });
6983               })
6984               .controller('GreeterController', ['$scope', function($scope) {
6985                 $scope.name = 'Angular';
6986                 $scope.html = 'Hello {{name}}';
6987               }]);
6988             </script>
6989             <div ng-controller="GreeterController">
6990               <input ng-model="name"> <br/>
6991               <textarea ng-model="html"></textarea> <br/>
6992               <div compile="html"></div>
6993             </div>
6994            </file>
6995            <file name="protractor.js" type="protractor">
6996              it('should auto compile', function() {
6997                var textarea = $('textarea');
6998                var output = $('div[compile]');
6999                // The initial state reads 'Hello Angular'.
7000                expect(output.getText()).toBe('Hello Angular');
7001                textarea.clear();
7002                textarea.sendKeys('{{name}}!');
7003                expect(output.getText()).toBe('Angular!');
7004              });
7005            </file>
7006          </example>
7007
7008          *
7009          *
7010          * @param {string|DOMElement} element Element or HTML string to compile into a template function.
7011          * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
7012          *
7013          * <div class="alert alert-danger">
7014          * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
7015          *   e.g. will not use the right outer scope. Please pass the transclude function as a
7016          *   `parentBoundTranscludeFn` to the link function instead.
7017          * </div>
7018          *
7019          * @param {number} maxPriority only apply directives lower than given priority (Only effects the
7020          *                 root element(s), not their children)
7021          * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
7022          * (a DOM element/tree) to a scope. Where:
7023          *
7024          *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
7025          *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
7026          *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
7027          *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
7028          *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
7029          *
7030          *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
7031          *      * `scope` - is the current scope with which the linking function is working with.
7032          *
7033          *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
7034          *  keys may be used to control linking behavior:
7035          *
7036          *      * `parentBoundTranscludeFn` - the transclude function made available to
7037          *        directives; if given, it will be passed through to the link functions of
7038          *        directives found in `element` during compilation.
7039          *      * `transcludeControllers` - an object hash with keys that map controller names
7040          *        to controller instances; if given, it will make the controllers
7041          *        available to directives.
7042          *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
7043          *        the cloned elements; only needed for transcludes that are allowed to contain non html
7044          *        elements (e.g. SVG elements). See also the directive.controller property.
7045          *
7046          * Calling the linking function returns the element of the template. It is either the original
7047          * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
7048          *
7049          * After linking the view is not updated until after a call to $digest which typically is done by
7050          * Angular automatically.
7051          *
7052          * If you need access to the bound view, there are two ways to do it:
7053          *
7054          * - If you are not asking the linking function to clone the template, create the DOM element(s)
7055          *   before you send them to the compiler and keep this reference around.
7056          *   ```js
7057          *     var element = $compile('<p>{{total}}</p>')(scope);
7058          *   ```
7059          *
7060          * - if on the other hand, you need the element to be cloned, the view reference from the original
7061          *   example would not point to the clone, but rather to the original template that was cloned. In
7062          *   this case, you can access the clone via the cloneAttachFn:
7063          *   ```js
7064          *     var templateElement = angular.element('<p>{{total}}</p>'),
7065          *         scope = ....;
7066          *
7067          *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
7068          *       //attach the clone to DOM document at the right place
7069          *     });
7070          *
7071          *     //now we have reference to the cloned DOM via `clonedElement`
7072          *   ```
7073          *
7074          *
7075          * For information on how the compiler works, see the
7076          * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
7077          */
7078
7079         var $compileMinErr = minErr('$compile');
7080
7081         /**
7082          * @ngdoc provider
7083          * @name $compileProvider
7084          *
7085          * @description
7086          */
7087         $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
7088         function $CompileProvider($provide, $$sanitizeUriProvider) {
7089           var hasDirectives = {},
7090               Suffix = 'Directive',
7091               COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
7092               CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
7093               ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
7094               REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
7095
7096           // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
7097           // The assumption is that future DOM event attribute names will begin with
7098           // 'on' and be composed of only English letters.
7099           var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
7100
7101           function parseIsolateBindings(scope, directiveName, isController) {
7102             var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
7103
7104             var bindings = {};
7105
7106             forEach(scope, function(definition, scopeName) {
7107               var match = definition.match(LOCAL_REGEXP);
7108
7109               if (!match) {
7110                 throw $compileMinErr('iscp',
7111                     "Invalid {3} for directive '{0}'." +
7112                     " Definition: {... {1}: '{2}' ...}",
7113                     directiveName, scopeName, definition,
7114                     (isController ? "controller bindings definition" :
7115                     "isolate scope definition"));
7116               }
7117
7118               bindings[scopeName] = {
7119                 mode: match[1][0],
7120                 collection: match[2] === '*',
7121                 optional: match[3] === '?',
7122                 attrName: match[4] || scopeName
7123               };
7124             });
7125
7126             return bindings;
7127           }
7128
7129           function parseDirectiveBindings(directive, directiveName) {
7130             var bindings = {
7131               isolateScope: null,
7132               bindToController: null
7133             };
7134             if (isObject(directive.scope)) {
7135               if (directive.bindToController === true) {
7136                 bindings.bindToController = parseIsolateBindings(directive.scope,
7137                                                                  directiveName, true);
7138                 bindings.isolateScope = {};
7139               } else {
7140                 bindings.isolateScope = parseIsolateBindings(directive.scope,
7141                                                              directiveName, false);
7142               }
7143             }
7144             if (isObject(directive.bindToController)) {
7145               bindings.bindToController =
7146                   parseIsolateBindings(directive.bindToController, directiveName, true);
7147             }
7148             if (isObject(bindings.bindToController)) {
7149               var controller = directive.controller;
7150               var controllerAs = directive.controllerAs;
7151               if (!controller) {
7152                 // There is no controller, there may or may not be a controllerAs property
7153                 throw $compileMinErr('noctrl',
7154                       "Cannot bind to controller without directive '{0}'s controller.",
7155                       directiveName);
7156               } else if (!identifierForController(controller, controllerAs)) {
7157                 // There is a controller, but no identifier or controllerAs property
7158                 throw $compileMinErr('noident',
7159                       "Cannot bind to controller without identifier for directive '{0}'.",
7160                       directiveName);
7161               }
7162             }
7163             return bindings;
7164           }
7165
7166           function assertValidDirectiveName(name) {
7167             var letter = name.charAt(0);
7168             if (!letter || letter !== lowercase(letter)) {
7169               throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
7170             }
7171             if (name !== name.trim()) {
7172               throw $compileMinErr('baddir',
7173                     "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
7174                     name);
7175             }
7176           }
7177
7178           /**
7179            * @ngdoc method
7180            * @name $compileProvider#directive
7181            * @kind function
7182            *
7183            * @description
7184            * Register a new directive with the compiler.
7185            *
7186            * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
7187            *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
7188            *    names and the values are the factories.
7189            * @param {Function|Array} directiveFactory An injectable directive factory function. See
7190            *    {@link guide/directive} for more info.
7191            * @returns {ng.$compileProvider} Self for chaining.
7192            */
7193            this.directive = function registerDirective(name, directiveFactory) {
7194             assertNotHasOwnProperty(name, 'directive');
7195             if (isString(name)) {
7196               assertValidDirectiveName(name);
7197               assertArg(directiveFactory, 'directiveFactory');
7198               if (!hasDirectives.hasOwnProperty(name)) {
7199                 hasDirectives[name] = [];
7200                 $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
7201                   function($injector, $exceptionHandler) {
7202                     var directives = [];
7203                     forEach(hasDirectives[name], function(directiveFactory, index) {
7204                       try {
7205                         var directive = $injector.invoke(directiveFactory);
7206                         if (isFunction(directive)) {
7207                           directive = { compile: valueFn(directive) };
7208                         } else if (!directive.compile && directive.link) {
7209                           directive.compile = valueFn(directive.link);
7210                         }
7211                         directive.priority = directive.priority || 0;
7212                         directive.index = index;
7213                         directive.name = directive.name || name;
7214                         directive.require = directive.require || (directive.controller && directive.name);
7215                         directive.restrict = directive.restrict || 'EA';
7216                         var bindings = directive.$$bindings =
7217                             parseDirectiveBindings(directive, directive.name);
7218                         if (isObject(bindings.isolateScope)) {
7219                           directive.$$isolateBindings = bindings.isolateScope;
7220                         }
7221                         directive.$$moduleName = directiveFactory.$$moduleName;
7222                         directives.push(directive);
7223                       } catch (e) {
7224                         $exceptionHandler(e);
7225                       }
7226                     });
7227                     return directives;
7228                   }]);
7229               }
7230               hasDirectives[name].push(directiveFactory);
7231             } else {
7232               forEach(name, reverseParams(registerDirective));
7233             }
7234             return this;
7235           };
7236
7237
7238           /**
7239            * @ngdoc method
7240            * @name $compileProvider#aHrefSanitizationWhitelist
7241            * @kind function
7242            *
7243            * @description
7244            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
7245            * urls during a[href] sanitization.
7246            *
7247            * The sanitization is a security measure aimed at preventing XSS attacks via html links.
7248            *
7249            * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
7250            * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
7251            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
7252            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
7253            *
7254            * @param {RegExp=} regexp New regexp to whitelist urls with.
7255            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
7256            *    chaining otherwise.
7257            */
7258           this.aHrefSanitizationWhitelist = function(regexp) {
7259             if (isDefined(regexp)) {
7260               $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
7261               return this;
7262             } else {
7263               return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
7264             }
7265           };
7266
7267
7268           /**
7269            * @ngdoc method
7270            * @name $compileProvider#imgSrcSanitizationWhitelist
7271            * @kind function
7272            *
7273            * @description
7274            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
7275            * urls during img[src] sanitization.
7276            *
7277            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
7278            *
7279            * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
7280            * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
7281            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
7282            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
7283            *
7284            * @param {RegExp=} regexp New regexp to whitelist urls with.
7285            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
7286            *    chaining otherwise.
7287            */
7288           this.imgSrcSanitizationWhitelist = function(regexp) {
7289             if (isDefined(regexp)) {
7290               $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
7291               return this;
7292             } else {
7293               return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
7294             }
7295           };
7296
7297           /**
7298            * @ngdoc method
7299            * @name  $compileProvider#debugInfoEnabled
7300            *
7301            * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
7302            * current debugInfoEnabled state
7303            * @returns {*} current value if used as getter or itself (chaining) if used as setter
7304            *
7305            * @kind function
7306            *
7307            * @description
7308            * Call this method to enable/disable various debug runtime information in the compiler such as adding
7309            * binding information and a reference to the current scope on to DOM elements.
7310            * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
7311            * * `ng-binding` CSS class
7312            * * `$binding` data property containing an array of the binding expressions
7313            *
7314            * You may want to disable this in production for a significant performance boost. See
7315            * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
7316            *
7317            * The default value is true.
7318            */
7319           var debugInfoEnabled = true;
7320           this.debugInfoEnabled = function(enabled) {
7321             if (isDefined(enabled)) {
7322               debugInfoEnabled = enabled;
7323               return this;
7324             }
7325             return debugInfoEnabled;
7326           };
7327
7328           this.$get = [
7329                     '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
7330                     '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
7331             function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
7332                      $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
7333
7334             var Attributes = function(element, attributesToCopy) {
7335               if (attributesToCopy) {
7336                 var keys = Object.keys(attributesToCopy);
7337                 var i, l, key;
7338
7339                 for (i = 0, l = keys.length; i < l; i++) {
7340                   key = keys[i];
7341                   this[key] = attributesToCopy[key];
7342                 }
7343               } else {
7344                 this.$attr = {};
7345               }
7346
7347               this.$$element = element;
7348             };
7349
7350             Attributes.prototype = {
7351               /**
7352                * @ngdoc method
7353                * @name $compile.directive.Attributes#$normalize
7354                * @kind function
7355                *
7356                * @description
7357                * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
7358                * `data-`) to its normalized, camelCase form.
7359                *
7360                * Also there is special case for Moz prefix starting with upper case letter.
7361                *
7362                * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
7363                *
7364                * @param {string} name Name to normalize
7365                */
7366               $normalize: directiveNormalize,
7367
7368
7369               /**
7370                * @ngdoc method
7371                * @name $compile.directive.Attributes#$addClass
7372                * @kind function
7373                *
7374                * @description
7375                * Adds the CSS class value specified by the classVal parameter to the element. If animations
7376                * are enabled then an animation will be triggered for the class addition.
7377                *
7378                * @param {string} classVal The className value that will be added to the element
7379                */
7380               $addClass: function(classVal) {
7381                 if (classVal && classVal.length > 0) {
7382                   $animate.addClass(this.$$element, classVal);
7383                 }
7384               },
7385
7386               /**
7387                * @ngdoc method
7388                * @name $compile.directive.Attributes#$removeClass
7389                * @kind function
7390                *
7391                * @description
7392                * Removes the CSS class value specified by the classVal parameter from the element. If
7393                * animations are enabled then an animation will be triggered for the class removal.
7394                *
7395                * @param {string} classVal The className value that will be removed from the element
7396                */
7397               $removeClass: function(classVal) {
7398                 if (classVal && classVal.length > 0) {
7399                   $animate.removeClass(this.$$element, classVal);
7400                 }
7401               },
7402
7403               /**
7404                * @ngdoc method
7405                * @name $compile.directive.Attributes#$updateClass
7406                * @kind function
7407                *
7408                * @description
7409                * Adds and removes the appropriate CSS class values to the element based on the difference
7410                * between the new and old CSS class values (specified as newClasses and oldClasses).
7411                *
7412                * @param {string} newClasses The current CSS className value
7413                * @param {string} oldClasses The former CSS className value
7414                */
7415               $updateClass: function(newClasses, oldClasses) {
7416                 var toAdd = tokenDifference(newClasses, oldClasses);
7417                 if (toAdd && toAdd.length) {
7418                   $animate.addClass(this.$$element, toAdd);
7419                 }
7420
7421                 var toRemove = tokenDifference(oldClasses, newClasses);
7422                 if (toRemove && toRemove.length) {
7423                   $animate.removeClass(this.$$element, toRemove);
7424                 }
7425               },
7426
7427               /**
7428                * Set a normalized attribute on the element in a way such that all directives
7429                * can share the attribute. This function properly handles boolean attributes.
7430                * @param {string} key Normalized key. (ie ngAttribute)
7431                * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
7432                * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
7433                *     Defaults to true.
7434                * @param {string=} attrName Optional none normalized name. Defaults to key.
7435                */
7436               $set: function(key, value, writeAttr, attrName) {
7437                 // TODO: decide whether or not to throw an error if "class"
7438                 //is set through this function since it may cause $updateClass to
7439                 //become unstable.
7440
7441                 var node = this.$$element[0],
7442                     booleanKey = getBooleanAttrName(node, key),
7443                     aliasedKey = getAliasedAttrName(key),
7444                     observer = key,
7445                     nodeName;
7446
7447                 if (booleanKey) {
7448                   this.$$element.prop(key, value);
7449                   attrName = booleanKey;
7450                 } else if (aliasedKey) {
7451                   this[aliasedKey] = value;
7452                   observer = aliasedKey;
7453                 }
7454
7455                 this[key] = value;
7456
7457                 // translate normalized key to actual key
7458                 if (attrName) {
7459                   this.$attr[key] = attrName;
7460                 } else {
7461                   attrName = this.$attr[key];
7462                   if (!attrName) {
7463                     this.$attr[key] = attrName = snake_case(key, '-');
7464                   }
7465                 }
7466
7467                 nodeName = nodeName_(this.$$element);
7468
7469                 if ((nodeName === 'a' && key === 'href') ||
7470                     (nodeName === 'img' && key === 'src')) {
7471                   // sanitize a[href] and img[src] values
7472                   this[key] = value = $$sanitizeUri(value, key === 'src');
7473                 } else if (nodeName === 'img' && key === 'srcset') {
7474                   // sanitize img[srcset] values
7475                   var result = "";
7476
7477                   // first check if there are spaces because it's not the same pattern
7478                   var trimmedSrcset = trim(value);
7479                   //                (   999x   ,|   999w   ,|   ,|,   )
7480                   var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
7481                   var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
7482
7483                   // split srcset into tuple of uri and descriptor except for the last item
7484                   var rawUris = trimmedSrcset.split(pattern);
7485
7486                   // for each tuples
7487                   var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
7488                   for (var i = 0; i < nbrUrisWith2parts; i++) {
7489                     var innerIdx = i * 2;
7490                     // sanitize the uri
7491                     result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
7492                     // add the descriptor
7493                     result += (" " + trim(rawUris[innerIdx + 1]));
7494                   }
7495
7496                   // split the last item into uri and descriptor
7497                   var lastTuple = trim(rawUris[i * 2]).split(/\s/);
7498
7499                   // sanitize the last uri
7500                   result += $$sanitizeUri(trim(lastTuple[0]), true);
7501
7502                   // and add the last descriptor if any
7503                   if (lastTuple.length === 2) {
7504                     result += (" " + trim(lastTuple[1]));
7505                   }
7506                   this[key] = value = result;
7507                 }
7508
7509                 if (writeAttr !== false) {
7510                   if (value === null || isUndefined(value)) {
7511                     this.$$element.removeAttr(attrName);
7512                   } else {
7513                     this.$$element.attr(attrName, value);
7514                   }
7515                 }
7516
7517                 // fire observers
7518                 var $$observers = this.$$observers;
7519                 $$observers && forEach($$observers[observer], function(fn) {
7520                   try {
7521                     fn(value);
7522                   } catch (e) {
7523                     $exceptionHandler(e);
7524                   }
7525                 });
7526               },
7527
7528
7529               /**
7530                * @ngdoc method
7531                * @name $compile.directive.Attributes#$observe
7532                * @kind function
7533                *
7534                * @description
7535                * Observes an interpolated attribute.
7536                *
7537                * The observer function will be invoked once during the next `$digest` following
7538                * compilation. The observer is then invoked whenever the interpolated value
7539                * changes.
7540                *
7541                * @param {string} key Normalized key. (ie ngAttribute) .
7542                * @param {function(interpolatedValue)} fn Function that will be called whenever
7543                         the interpolated value of the attribute changes.
7544                *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
7545                * @returns {function()} Returns a deregistration function for this observer.
7546                */
7547               $observe: function(key, fn) {
7548                 var attrs = this,
7549                     $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
7550                     listeners = ($$observers[key] || ($$observers[key] = []));
7551
7552                 listeners.push(fn);
7553                 $rootScope.$evalAsync(function() {
7554                   if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
7555                     // no one registered attribute interpolation function, so lets call it manually
7556                     fn(attrs[key]);
7557                   }
7558                 });
7559
7560                 return function() {
7561                   arrayRemove(listeners, fn);
7562                 };
7563               }
7564             };
7565
7566
7567             function safeAddClass($element, className) {
7568               try {
7569                 $element.addClass(className);
7570               } catch (e) {
7571                 // ignore, since it means that we are trying to set class on
7572                 // SVG element, where class name is read-only.
7573               }
7574             }
7575
7576
7577             var startSymbol = $interpolate.startSymbol(),
7578                 endSymbol = $interpolate.endSymbol(),
7579                 denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
7580                     ? identity
7581                     : function denormalizeTemplate(template) {
7582                       return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
7583                 },
7584                 NG_ATTR_BINDING = /^ngAttr[A-Z]/;
7585             var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
7586
7587             compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
7588               var bindings = $element.data('$binding') || [];
7589
7590               if (isArray(binding)) {
7591                 bindings = bindings.concat(binding);
7592               } else {
7593                 bindings.push(binding);
7594               }
7595
7596               $element.data('$binding', bindings);
7597             } : noop;
7598
7599             compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
7600               safeAddClass($element, 'ng-binding');
7601             } : noop;
7602
7603             compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
7604               var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
7605               $element.data(dataName, scope);
7606             } : noop;
7607
7608             compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
7609               safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
7610             } : noop;
7611
7612             return compile;
7613
7614             //================================
7615
7616             function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
7617                                 previousCompileContext) {
7618               if (!($compileNodes instanceof jqLite)) {
7619                 // jquery always rewraps, whereas we need to preserve the original selector so that we can
7620                 // modify it.
7621                 $compileNodes = jqLite($compileNodes);
7622               }
7623               // We can not compile top level text elements since text nodes can be merged and we will
7624               // not be able to attach scope data to them, so we will wrap them in <span>
7625               forEach($compileNodes, function(node, index) {
7626                 if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
7627                   $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
7628                 }
7629               });
7630               var compositeLinkFn =
7631                       compileNodes($compileNodes, transcludeFn, $compileNodes,
7632                                    maxPriority, ignoreDirective, previousCompileContext);
7633               compile.$$addScopeClass($compileNodes);
7634               var namespace = null;
7635               return function publicLinkFn(scope, cloneConnectFn, options) {
7636                 assertArg(scope, 'scope');
7637
7638                 if (previousCompileContext && previousCompileContext.needsNewScope) {
7639                   // A parent directive did a replace and a directive on this element asked
7640                   // for transclusion, which caused us to lose a layer of element on which
7641                   // we could hold the new transclusion scope, so we will create it manually
7642                   // here.
7643                   scope = scope.$parent.$new();
7644                 }
7645
7646                 options = options || {};
7647                 var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
7648                   transcludeControllers = options.transcludeControllers,
7649                   futureParentElement = options.futureParentElement;
7650
7651                 // When `parentBoundTranscludeFn` is passed, it is a
7652                 // `controllersBoundTransclude` function (it was previously passed
7653                 // as `transclude` to directive.link) so we must unwrap it to get
7654                 // its `boundTranscludeFn`
7655                 if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
7656                   parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
7657                 }
7658
7659                 if (!namespace) {
7660                   namespace = detectNamespaceForChildElements(futureParentElement);
7661                 }
7662                 var $linkNode;
7663                 if (namespace !== 'html') {
7664                   // When using a directive with replace:true and templateUrl the $compileNodes
7665                   // (or a child element inside of them)
7666                   // might change, so we need to recreate the namespace adapted compileNodes
7667                   // for call to the link function.
7668                   // Note: This will already clone the nodes...
7669                   $linkNode = jqLite(
7670                     wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
7671                   );
7672                 } else if (cloneConnectFn) {
7673                   // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
7674                   // and sometimes changes the structure of the DOM.
7675                   $linkNode = JQLitePrototype.clone.call($compileNodes);
7676                 } else {
7677                   $linkNode = $compileNodes;
7678                 }
7679
7680                 if (transcludeControllers) {
7681                   for (var controllerName in transcludeControllers) {
7682                     $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
7683                   }
7684                 }
7685
7686                 compile.$$addScopeInfo($linkNode, scope);
7687
7688                 if (cloneConnectFn) cloneConnectFn($linkNode, scope);
7689                 if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
7690                 return $linkNode;
7691               };
7692             }
7693
7694             function detectNamespaceForChildElements(parentElement) {
7695               // TODO: Make this detect MathML as well...
7696               var node = parentElement && parentElement[0];
7697               if (!node) {
7698                 return 'html';
7699               } else {
7700                 return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
7701               }
7702             }
7703
7704             /**
7705              * Compile function matches each node in nodeList against the directives. Once all directives
7706              * for a particular node are collected their compile functions are executed. The compile
7707              * functions return values - the linking functions - are combined into a composite linking
7708              * function, which is the a linking function for the node.
7709              *
7710              * @param {NodeList} nodeList an array of nodes or NodeList to compile
7711              * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7712              *        scope argument is auto-generated to the new child of the transcluded parent scope.
7713              * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
7714              *        the rootElement must be set the jqLite collection of the compile root. This is
7715              *        needed so that the jqLite collection items can be replaced with widgets.
7716              * @param {number=} maxPriority Max directive priority.
7717              * @returns {Function} A composite linking function of all of the matched directives or null.
7718              */
7719             function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
7720                                     previousCompileContext) {
7721               var linkFns = [],
7722                   attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
7723
7724               for (var i = 0; i < nodeList.length; i++) {
7725                 attrs = new Attributes();
7726
7727                 // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
7728                 directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
7729                                                 ignoreDirective);
7730
7731                 nodeLinkFn = (directives.length)
7732                     ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
7733                                               null, [], [], previousCompileContext)
7734                     : null;
7735
7736                 if (nodeLinkFn && nodeLinkFn.scope) {
7737                   compile.$$addScopeClass(attrs.$$element);
7738                 }
7739
7740                 childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
7741                               !(childNodes = nodeList[i].childNodes) ||
7742                               !childNodes.length)
7743                     ? null
7744                     : compileNodes(childNodes,
7745                          nodeLinkFn ? (
7746                           (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
7747                              && nodeLinkFn.transclude) : transcludeFn);
7748
7749                 if (nodeLinkFn || childLinkFn) {
7750                   linkFns.push(i, nodeLinkFn, childLinkFn);
7751                   linkFnFound = true;
7752                   nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
7753                 }
7754
7755                 //use the previous context only for the first element in the virtual group
7756                 previousCompileContext = null;
7757               }
7758
7759               // return a linking function if we have found anything, null otherwise
7760               return linkFnFound ? compositeLinkFn : null;
7761
7762               function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
7763                 var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
7764                 var stableNodeList;
7765
7766
7767                 if (nodeLinkFnFound) {
7768                   // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
7769                   // offsets don't get screwed up
7770                   var nodeListLength = nodeList.length;
7771                   stableNodeList = new Array(nodeListLength);
7772
7773                   // create a sparse array by only copying the elements which have a linkFn
7774                   for (i = 0; i < linkFns.length; i+=3) {
7775                     idx = linkFns[i];
7776                     stableNodeList[idx] = nodeList[idx];
7777                   }
7778                 } else {
7779                   stableNodeList = nodeList;
7780                 }
7781
7782                 for (i = 0, ii = linkFns.length; i < ii;) {
7783                   node = stableNodeList[linkFns[i++]];
7784                   nodeLinkFn = linkFns[i++];
7785                   childLinkFn = linkFns[i++];
7786
7787                   if (nodeLinkFn) {
7788                     if (nodeLinkFn.scope) {
7789                       childScope = scope.$new();
7790                       compile.$$addScopeInfo(jqLite(node), childScope);
7791                     } else {
7792                       childScope = scope;
7793                     }
7794
7795                     if (nodeLinkFn.transcludeOnThisElement) {
7796                       childBoundTranscludeFn = createBoundTranscludeFn(
7797                           scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
7798
7799                     } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
7800                       childBoundTranscludeFn = parentBoundTranscludeFn;
7801
7802                     } else if (!parentBoundTranscludeFn && transcludeFn) {
7803                       childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
7804
7805                     } else {
7806                       childBoundTranscludeFn = null;
7807                     }
7808
7809                     nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
7810
7811                   } else if (childLinkFn) {
7812                     childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
7813                   }
7814                 }
7815               }
7816             }
7817
7818             function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
7819
7820               var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
7821
7822                 if (!transcludedScope) {
7823                   transcludedScope = scope.$new(false, containingScope);
7824                   transcludedScope.$$transcluded = true;
7825                 }
7826
7827                 return transcludeFn(transcludedScope, cloneFn, {
7828                   parentBoundTranscludeFn: previousBoundTranscludeFn,
7829                   transcludeControllers: controllers,
7830                   futureParentElement: futureParentElement
7831                 });
7832               };
7833
7834               return boundTranscludeFn;
7835             }
7836
7837             /**
7838              * Looks for directives on the given node and adds them to the directive collection which is
7839              * sorted.
7840              *
7841              * @param node Node to search.
7842              * @param directives An array to which the directives are added to. This array is sorted before
7843              *        the function returns.
7844              * @param attrs The shared attrs object which is used to populate the normalized attributes.
7845              * @param {number=} maxPriority Max directive priority.
7846              */
7847             function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
7848               var nodeType = node.nodeType,
7849                   attrsMap = attrs.$attr,
7850                   match,
7851                   className;
7852
7853               switch (nodeType) {
7854                 case NODE_TYPE_ELEMENT: /* Element */
7855                   // use the node name: <directive>
7856                   addDirective(directives,
7857                       directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
7858
7859                   // iterate over the attributes
7860                   for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
7861                            j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
7862                     var attrStartName = false;
7863                     var attrEndName = false;
7864
7865                     attr = nAttrs[j];
7866                     name = attr.name;
7867                     value = trim(attr.value);
7868
7869                     // support ngAttr attribute binding
7870                     ngAttrName = directiveNormalize(name);
7871                     if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
7872                       name = name.replace(PREFIX_REGEXP, '')
7873                         .substr(8).replace(/_(.)/g, function(match, letter) {
7874                           return letter.toUpperCase();
7875                         });
7876                     }
7877
7878                     var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
7879                     if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
7880                       attrStartName = name;
7881                       attrEndName = name.substr(0, name.length - 5) + 'end';
7882                       name = name.substr(0, name.length - 6);
7883                     }
7884
7885                     nName = directiveNormalize(name.toLowerCase());
7886                     attrsMap[nName] = name;
7887                     if (isNgAttr || !attrs.hasOwnProperty(nName)) {
7888                         attrs[nName] = value;
7889                         if (getBooleanAttrName(node, nName)) {
7890                           attrs[nName] = true; // presence means true
7891                         }
7892                     }
7893                     addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
7894                     addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
7895                                   attrEndName);
7896                   }
7897
7898                   // use class as directive
7899                   className = node.className;
7900                   if (isObject(className)) {
7901                       // Maybe SVGAnimatedString
7902                       className = className.animVal;
7903                   }
7904                   if (isString(className) && className !== '') {
7905                     while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
7906                       nName = directiveNormalize(match[2]);
7907                       if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
7908                         attrs[nName] = trim(match[3]);
7909                       }
7910                       className = className.substr(match.index + match[0].length);
7911                     }
7912                   }
7913                   break;
7914                 case NODE_TYPE_TEXT: /* Text Node */
7915                   if (msie === 11) {
7916                     // Workaround for #11781
7917                     while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
7918                       node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
7919                       node.parentNode.removeChild(node.nextSibling);
7920                     }
7921                   }
7922                   addTextInterpolateDirective(directives, node.nodeValue);
7923                   break;
7924                 case NODE_TYPE_COMMENT: /* Comment */
7925                   try {
7926                     match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
7927                     if (match) {
7928                       nName = directiveNormalize(match[1]);
7929                       if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
7930                         attrs[nName] = trim(match[2]);
7931                       }
7932                     }
7933                   } catch (e) {
7934                     // turns out that under some circumstances IE9 throws errors when one attempts to read
7935                     // comment's node value.
7936                     // Just ignore it and continue. (Can't seem to reproduce in test case.)
7937                   }
7938                   break;
7939               }
7940
7941               directives.sort(byPriority);
7942               return directives;
7943             }
7944
7945             /**
7946              * Given a node with an directive-start it collects all of the siblings until it finds
7947              * directive-end.
7948              * @param node
7949              * @param attrStart
7950              * @param attrEnd
7951              * @returns {*}
7952              */
7953             function groupScan(node, attrStart, attrEnd) {
7954               var nodes = [];
7955               var depth = 0;
7956               if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
7957                 do {
7958                   if (!node) {
7959                     throw $compileMinErr('uterdir',
7960                               "Unterminated attribute, found '{0}' but no matching '{1}' found.",
7961                               attrStart, attrEnd);
7962                   }
7963                   if (node.nodeType == NODE_TYPE_ELEMENT) {
7964                     if (node.hasAttribute(attrStart)) depth++;
7965                     if (node.hasAttribute(attrEnd)) depth--;
7966                   }
7967                   nodes.push(node);
7968                   node = node.nextSibling;
7969                 } while (depth > 0);
7970               } else {
7971                 nodes.push(node);
7972               }
7973
7974               return jqLite(nodes);
7975             }
7976
7977             /**
7978              * Wrapper for linking function which converts normal linking function into a grouped
7979              * linking function.
7980              * @param linkFn
7981              * @param attrStart
7982              * @param attrEnd
7983              * @returns {Function}
7984              */
7985             function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
7986               return function(scope, element, attrs, controllers, transcludeFn) {
7987                 element = groupScan(element[0], attrStart, attrEnd);
7988                 return linkFn(scope, element, attrs, controllers, transcludeFn);
7989               };
7990             }
7991
7992             /**
7993              * Once the directives have been collected, their compile functions are executed. This method
7994              * is responsible for inlining directive templates as well as terminating the application
7995              * of the directives if the terminal directive has been reached.
7996              *
7997              * @param {Array} directives Array of collected directives to execute their compile function.
7998              *        this needs to be pre-sorted by priority order.
7999              * @param {Node} compileNode The raw DOM node to apply the compile functions to
8000              * @param {Object} templateAttrs The shared attribute function
8001              * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
8002              *                                                  scope argument is auto-generated to the new
8003              *                                                  child of the transcluded parent scope.
8004              * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
8005              *                              argument has the root jqLite array so that we can replace nodes
8006              *                              on it.
8007              * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
8008              *                                           compiling the transclusion.
8009              * @param {Array.<Function>} preLinkFns
8010              * @param {Array.<Function>} postLinkFns
8011              * @param {Object} previousCompileContext Context used for previous compilation of the current
8012              *                                        node
8013              * @returns {Function} linkFn
8014              */
8015             function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
8016                                            jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
8017                                            previousCompileContext) {
8018               previousCompileContext = previousCompileContext || {};
8019
8020               var terminalPriority = -Number.MAX_VALUE,
8021                   newScopeDirective = previousCompileContext.newScopeDirective,
8022                   controllerDirectives = previousCompileContext.controllerDirectives,
8023                   newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
8024                   templateDirective = previousCompileContext.templateDirective,
8025                   nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
8026                   hasTranscludeDirective = false,
8027                   hasTemplate = false,
8028                   hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
8029                   $compileNode = templateAttrs.$$element = jqLite(compileNode),
8030                   directive,
8031                   directiveName,
8032                   $template,
8033                   replaceDirective = originalReplaceDirective,
8034                   childTranscludeFn = transcludeFn,
8035                   linkFn,
8036                   directiveValue;
8037
8038               // executes all directives on the current element
8039               for (var i = 0, ii = directives.length; i < ii; i++) {
8040                 directive = directives[i];
8041                 var attrStart = directive.$$start;
8042                 var attrEnd = directive.$$end;
8043
8044                 // collect multiblock sections
8045                 if (attrStart) {
8046                   $compileNode = groupScan(compileNode, attrStart, attrEnd);
8047                 }
8048                 $template = undefined;
8049
8050                 if (terminalPriority > directive.priority) {
8051                   break; // prevent further processing of directives
8052                 }
8053
8054                 if (directiveValue = directive.scope) {
8055
8056                   // skip the check for directives with async templates, we'll check the derived sync
8057                   // directive when the template arrives
8058                   if (!directive.templateUrl) {
8059                     if (isObject(directiveValue)) {
8060                       // This directive is trying to add an isolated scope.
8061                       // Check that there is no scope of any kind already
8062                       assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
8063                                         directive, $compileNode);
8064                       newIsolateScopeDirective = directive;
8065                     } else {
8066                       // This directive is trying to add a child scope.
8067                       // Check that there is no isolated scope already
8068                       assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
8069                                         $compileNode);
8070                     }
8071                   }
8072
8073                   newScopeDirective = newScopeDirective || directive;
8074                 }
8075
8076                 directiveName = directive.name;
8077
8078                 if (!directive.templateUrl && directive.controller) {
8079                   directiveValue = directive.controller;
8080                   controllerDirectives = controllerDirectives || createMap();
8081                   assertNoDuplicate("'" + directiveName + "' controller",
8082                       controllerDirectives[directiveName], directive, $compileNode);
8083                   controllerDirectives[directiveName] = directive;
8084                 }
8085
8086                 if (directiveValue = directive.transclude) {
8087                   hasTranscludeDirective = true;
8088
8089                   // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
8090                   // This option should only be used by directives that know how to safely handle element transclusion,
8091                   // where the transcluded nodes are added or replaced after linking.
8092                   if (!directive.$$tlb) {
8093                     assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
8094                     nonTlbTranscludeDirective = directive;
8095                   }
8096
8097                   if (directiveValue == 'element') {
8098                     hasElementTranscludeDirective = true;
8099                     terminalPriority = directive.priority;
8100                     $template = $compileNode;
8101                     $compileNode = templateAttrs.$$element =
8102                         jqLite(document.createComment(' ' + directiveName + ': ' +
8103                                                       templateAttrs[directiveName] + ' '));
8104                     compileNode = $compileNode[0];
8105                     replaceWith(jqCollection, sliceArgs($template), compileNode);
8106
8107                     childTranscludeFn = compile($template, transcludeFn, terminalPriority,
8108                                                 replaceDirective && replaceDirective.name, {
8109                                                   // Don't pass in:
8110                                                   // - controllerDirectives - otherwise we'll create duplicates controllers
8111                                                   // - newIsolateScopeDirective or templateDirective - combining templates with
8112                                                   //   element transclusion doesn't make sense.
8113                                                   //
8114                                                   // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
8115                                                   // on the same element more than once.
8116                                                   nonTlbTranscludeDirective: nonTlbTranscludeDirective
8117                                                 });
8118                   } else {
8119                     $template = jqLite(jqLiteClone(compileNode)).contents();
8120                     $compileNode.empty(); // clear contents
8121                     childTranscludeFn = compile($template, transcludeFn, undefined,
8122                         undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
8123                   }
8124                 }
8125
8126                 if (directive.template) {
8127                   hasTemplate = true;
8128                   assertNoDuplicate('template', templateDirective, directive, $compileNode);
8129                   templateDirective = directive;
8130
8131                   directiveValue = (isFunction(directive.template))
8132                       ? directive.template($compileNode, templateAttrs)
8133                       : directive.template;
8134
8135                   directiveValue = denormalizeTemplate(directiveValue);
8136
8137                   if (directive.replace) {
8138                     replaceDirective = directive;
8139                     if (jqLiteIsTextNode(directiveValue)) {
8140                       $template = [];
8141                     } else {
8142                       $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
8143                     }
8144                     compileNode = $template[0];
8145
8146                     if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8147                       throw $compileMinErr('tplrt',
8148                           "Template for directive '{0}' must have exactly one root element. {1}",
8149                           directiveName, '');
8150                     }
8151
8152                     replaceWith(jqCollection, $compileNode, compileNode);
8153
8154                     var newTemplateAttrs = {$attr: {}};
8155
8156                     // combine directives from the original node and from the template:
8157                     // - take the array of directives for this element
8158                     // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
8159                     // - collect directives from the template and sort them by priority
8160                     // - combine directives as: processed + template + unprocessed
8161                     var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
8162                     var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
8163
8164                     if (newIsolateScopeDirective || newScopeDirective) {
8165                       // The original directive caused the current element to be replaced but this element
8166                       // also needs to have a new scope, so we need to tell the template directives
8167                       // that they would need to get their scope from further up, if they require transclusion
8168                       markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
8169                     }
8170                     directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
8171                     mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
8172
8173                     ii = directives.length;
8174                   } else {
8175                     $compileNode.html(directiveValue);
8176                   }
8177                 }
8178
8179                 if (directive.templateUrl) {
8180                   hasTemplate = true;
8181                   assertNoDuplicate('template', templateDirective, directive, $compileNode);
8182                   templateDirective = directive;
8183
8184                   if (directive.replace) {
8185                     replaceDirective = directive;
8186                   }
8187
8188                   nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
8189                       templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
8190                         controllerDirectives: controllerDirectives,
8191                         newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
8192                         newIsolateScopeDirective: newIsolateScopeDirective,
8193                         templateDirective: templateDirective,
8194                         nonTlbTranscludeDirective: nonTlbTranscludeDirective
8195                       });
8196                   ii = directives.length;
8197                 } else if (directive.compile) {
8198                   try {
8199                     linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
8200                     if (isFunction(linkFn)) {
8201                       addLinkFns(null, linkFn, attrStart, attrEnd);
8202                     } else if (linkFn) {
8203                       addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
8204                     }
8205                   } catch (e) {
8206                     $exceptionHandler(e, startingTag($compileNode));
8207                   }
8208                 }
8209
8210                 if (directive.terminal) {
8211                   nodeLinkFn.terminal = true;
8212                   terminalPriority = Math.max(terminalPriority, directive.priority);
8213                 }
8214
8215               }
8216
8217               nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
8218               nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
8219               nodeLinkFn.templateOnThisElement = hasTemplate;
8220               nodeLinkFn.transclude = childTranscludeFn;
8221
8222               previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
8223
8224               // might be normal or delayed nodeLinkFn depending on if templateUrl is present
8225               return nodeLinkFn;
8226
8227               ////////////////////
8228
8229               function addLinkFns(pre, post, attrStart, attrEnd) {
8230                 if (pre) {
8231                   if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
8232                   pre.require = directive.require;
8233                   pre.directiveName = directiveName;
8234                   if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
8235                     pre = cloneAndAnnotateFn(pre, {isolateScope: true});
8236                   }
8237                   preLinkFns.push(pre);
8238                 }
8239                 if (post) {
8240                   if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
8241                   post.require = directive.require;
8242                   post.directiveName = directiveName;
8243                   if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
8244                     post = cloneAndAnnotateFn(post, {isolateScope: true});
8245                   }
8246                   postLinkFns.push(post);
8247                 }
8248               }
8249
8250
8251               function getControllers(directiveName, require, $element, elementControllers) {
8252                 var value;
8253
8254                 if (isString(require)) {
8255                   var match = require.match(REQUIRE_PREFIX_REGEXP);
8256                   var name = require.substring(match[0].length);
8257                   var inheritType = match[1] || match[3];
8258                   var optional = match[2] === '?';
8259
8260                   //If only parents then start at the parent element
8261                   if (inheritType === '^^') {
8262                     $element = $element.parent();
8263                   //Otherwise attempt getting the controller from elementControllers in case
8264                   //the element is transcluded (and has no data) and to avoid .data if possible
8265                   } else {
8266                     value = elementControllers && elementControllers[name];
8267                     value = value && value.instance;
8268                   }
8269
8270                   if (!value) {
8271                     var dataName = '$' + name + 'Controller';
8272                     value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
8273                   }
8274
8275                   if (!value && !optional) {
8276                     throw $compileMinErr('ctreq',
8277                         "Controller '{0}', required by directive '{1}', can't be found!",
8278                         name, directiveName);
8279                   }
8280                 } else if (isArray(require)) {
8281                   value = [];
8282                   for (var i = 0, ii = require.length; i < ii; i++) {
8283                     value[i] = getControllers(directiveName, require[i], $element, elementControllers);
8284                   }
8285                 }
8286
8287                 return value || null;
8288               }
8289
8290               function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
8291                 var elementControllers = createMap();
8292                 for (var controllerKey in controllerDirectives) {
8293                   var directive = controllerDirectives[controllerKey];
8294                   var locals = {
8295                     $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
8296                     $element: $element,
8297                     $attrs: attrs,
8298                     $transclude: transcludeFn
8299                   };
8300
8301                   var controller = directive.controller;
8302                   if (controller == '@') {
8303                     controller = attrs[directive.name];
8304                   }
8305
8306                   var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
8307
8308                   // For directives with element transclusion the element is a comment,
8309                   // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
8310                   // clean up (http://bugs.jquery.com/ticket/8335).
8311                   // Instead, we save the controllers for the element in a local hash and attach to .data
8312                   // later, once we have the actual element.
8313                   elementControllers[directive.name] = controllerInstance;
8314                   if (!hasElementTranscludeDirective) {
8315                     $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
8316                   }
8317                 }
8318                 return elementControllers;
8319               }
8320
8321               function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
8322                 var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8323                     attrs, removeScopeBindingWatches, removeControllerBindingWatches;
8324
8325                 if (compileNode === linkNode) {
8326                   attrs = templateAttrs;
8327                   $element = templateAttrs.$$element;
8328                 } else {
8329                   $element = jqLite(linkNode);
8330                   attrs = new Attributes($element, templateAttrs);
8331                 }
8332
8333                 controllerScope = scope;
8334                 if (newIsolateScopeDirective) {
8335                   isolateScope = scope.$new(true);
8336                 } else if (newScopeDirective) {
8337                   controllerScope = scope.$parent;
8338                 }
8339
8340                 if (boundTranscludeFn) {
8341                   // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
8342                   // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
8343                   transcludeFn = controllersBoundTransclude;
8344                   transcludeFn.$$boundTransclude = boundTranscludeFn;
8345                 }
8346
8347                 if (controllerDirectives) {
8348                   elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
8349                 }
8350
8351                 if (newIsolateScopeDirective) {
8352                   // Initialize isolate scope bindings for new isolate scope directive.
8353                   compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
8354                       templateDirective === newIsolateScopeDirective.$$originalDirective)));
8355                   compile.$$addScopeClass($element, true);
8356                   isolateScope.$$isolateBindings =
8357                       newIsolateScopeDirective.$$isolateBindings;
8358                   removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
8359                                                 isolateScope.$$isolateBindings,
8360                                                 newIsolateScopeDirective);
8361                   if (removeScopeBindingWatches) {
8362                     isolateScope.$on('$destroy', removeScopeBindingWatches);
8363                   }
8364                 }
8365
8366                 // Initialize bindToController bindings
8367                 for (var name in elementControllers) {
8368                   var controllerDirective = controllerDirectives[name];
8369                   var controller = elementControllers[name];
8370                   var bindings = controllerDirective.$$bindings.bindToController;
8371
8372                   if (controller.identifier && bindings) {
8373                     removeControllerBindingWatches =
8374                       initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8375                   }
8376
8377                   var controllerResult = controller();
8378                   if (controllerResult !== controller.instance) {
8379                     // If the controller constructor has a return value, overwrite the instance
8380                     // from setupControllers
8381                     controller.instance = controllerResult;
8382                     $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
8383                     removeControllerBindingWatches && removeControllerBindingWatches();
8384                     removeControllerBindingWatches =
8385                       initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8386                   }
8387                 }
8388
8389                 // PRELINKING
8390                 for (i = 0, ii = preLinkFns.length; i < ii; i++) {
8391                   linkFn = preLinkFns[i];
8392                   invokeLinkFn(linkFn,
8393                       linkFn.isolateScope ? isolateScope : scope,
8394                       $element,
8395                       attrs,
8396                       linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8397                       transcludeFn
8398                   );
8399                 }
8400
8401                 // RECURSION
8402                 // We only pass the isolate scope, if the isolate directive has a template,
8403                 // otherwise the child elements do not belong to the isolate directive.
8404                 var scopeToChild = scope;
8405                 if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
8406                   scopeToChild = isolateScope;
8407                 }
8408                 childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
8409
8410                 // POSTLINKING
8411                 for (i = postLinkFns.length - 1; i >= 0; i--) {
8412                   linkFn = postLinkFns[i];
8413                   invokeLinkFn(linkFn,
8414                       linkFn.isolateScope ? isolateScope : scope,
8415                       $element,
8416                       attrs,
8417                       linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8418                       transcludeFn
8419                   );
8420                 }
8421
8422                 // This is the function that is injected as `$transclude`.
8423                 // Note: all arguments are optional!
8424                 function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
8425                   var transcludeControllers;
8426
8427                   // No scope passed in:
8428                   if (!isScope(scope)) {
8429                     futureParentElement = cloneAttachFn;
8430                     cloneAttachFn = scope;
8431                     scope = undefined;
8432                   }
8433
8434                   if (hasElementTranscludeDirective) {
8435                     transcludeControllers = elementControllers;
8436                   }
8437                   if (!futureParentElement) {
8438                     futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
8439                   }
8440                   return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
8441                 }
8442               }
8443             }
8444
8445             // Depending upon the context in which a directive finds itself it might need to have a new isolated
8446             // or child scope created. For instance:
8447             // * if the directive has been pulled into a template because another directive with a higher priority
8448             // asked for element transclusion
8449             // * if the directive itself asks for transclusion but it is at the root of a template and the original
8450             // element was replaced. See https://github.com/angular/angular.js/issues/12936
8451             function markDirectiveScope(directives, isolateScope, newScope) {
8452               for (var j = 0, jj = directives.length; j < jj; j++) {
8453                 directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
8454               }
8455             }
8456
8457             /**
8458              * looks up the directive and decorates it with exception handling and proper parameters. We
8459              * call this the boundDirective.
8460              *
8461              * @param {string} name name of the directive to look up.
8462              * @param {string} location The directive must be found in specific format.
8463              *   String containing any of theses characters:
8464              *
8465              *   * `E`: element name
8466              *   * `A': attribute
8467              *   * `C`: class
8468              *   * `M`: comment
8469              * @returns {boolean} true if directive was added.
8470              */
8471             function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
8472                                   endAttrName) {
8473               if (name === ignoreDirective) return null;
8474               var match = null;
8475               if (hasDirectives.hasOwnProperty(name)) {
8476                 for (var directive, directives = $injector.get(name + Suffix),
8477                     i = 0, ii = directives.length; i < ii; i++) {
8478                   try {
8479                     directive = directives[i];
8480                     if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
8481                          directive.restrict.indexOf(location) != -1) {
8482                       if (startAttrName) {
8483                         directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
8484                       }
8485                       tDirectives.push(directive);
8486                       match = directive;
8487                     }
8488                   } catch (e) { $exceptionHandler(e); }
8489                 }
8490               }
8491               return match;
8492             }
8493
8494
8495             /**
8496              * looks up the directive and returns true if it is a multi-element directive,
8497              * and therefore requires DOM nodes between -start and -end markers to be grouped
8498              * together.
8499              *
8500              * @param {string} name name of the directive to look up.
8501              * @returns true if directive was registered as multi-element.
8502              */
8503             function directiveIsMultiElement(name) {
8504               if (hasDirectives.hasOwnProperty(name)) {
8505                 for (var directive, directives = $injector.get(name + Suffix),
8506                     i = 0, ii = directives.length; i < ii; i++) {
8507                   directive = directives[i];
8508                   if (directive.multiElement) {
8509                     return true;
8510                   }
8511                 }
8512               }
8513               return false;
8514             }
8515
8516             /**
8517              * When the element is replaced with HTML template then the new attributes
8518              * on the template need to be merged with the existing attributes in the DOM.
8519              * The desired effect is to have both of the attributes present.
8520              *
8521              * @param {object} dst destination attributes (original DOM)
8522              * @param {object} src source attributes (from the directive template)
8523              */
8524             function mergeTemplateAttributes(dst, src) {
8525               var srcAttr = src.$attr,
8526                   dstAttr = dst.$attr,
8527                   $element = dst.$$element;
8528
8529               // reapply the old attributes to the new element
8530               forEach(dst, function(value, key) {
8531                 if (key.charAt(0) != '$') {
8532                   if (src[key] && src[key] !== value) {
8533                     value += (key === 'style' ? ';' : ' ') + src[key];
8534                   }
8535                   dst.$set(key, value, true, srcAttr[key]);
8536                 }
8537               });
8538
8539               // copy the new attributes on the old attrs object
8540               forEach(src, function(value, key) {
8541                 if (key == 'class') {
8542                   safeAddClass($element, value);
8543                   dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
8544                 } else if (key == 'style') {
8545                   $element.attr('style', $element.attr('style') + ';' + value);
8546                   dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
8547                   // `dst` will never contain hasOwnProperty as DOM parser won't let it.
8548                   // You will get an "InvalidCharacterError: DOM Exception 5" error if you
8549                   // have an attribute like "has-own-property" or "data-has-own-property", etc.
8550                 } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
8551                   dst[key] = value;
8552                   dstAttr[key] = srcAttr[key];
8553                 }
8554               });
8555             }
8556
8557
8558             function compileTemplateUrl(directives, $compileNode, tAttrs,
8559                 $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
8560               var linkQueue = [],
8561                   afterTemplateNodeLinkFn,
8562                   afterTemplateChildLinkFn,
8563                   beforeTemplateCompileNode = $compileNode[0],
8564                   origAsyncDirective = directives.shift(),
8565                   derivedSyncDirective = inherit(origAsyncDirective, {
8566                     templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
8567                   }),
8568                   templateUrl = (isFunction(origAsyncDirective.templateUrl))
8569                       ? origAsyncDirective.templateUrl($compileNode, tAttrs)
8570                       : origAsyncDirective.templateUrl,
8571                   templateNamespace = origAsyncDirective.templateNamespace;
8572
8573               $compileNode.empty();
8574
8575               $templateRequest(templateUrl)
8576                 .then(function(content) {
8577                   var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
8578
8579                   content = denormalizeTemplate(content);
8580
8581                   if (origAsyncDirective.replace) {
8582                     if (jqLiteIsTextNode(content)) {
8583                       $template = [];
8584                     } else {
8585                       $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
8586                     }
8587                     compileNode = $template[0];
8588
8589                     if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8590                       throw $compileMinErr('tplrt',
8591                           "Template for directive '{0}' must have exactly one root element. {1}",
8592                           origAsyncDirective.name, templateUrl);
8593                     }
8594
8595                     tempTemplateAttrs = {$attr: {}};
8596                     replaceWith($rootElement, $compileNode, compileNode);
8597                     var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
8598
8599                     if (isObject(origAsyncDirective.scope)) {
8600                       // the original directive that caused the template to be loaded async required
8601                       // an isolate scope
8602                       markDirectiveScope(templateDirectives, true);
8603                     }
8604                     directives = templateDirectives.concat(directives);
8605                     mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
8606                   } else {
8607                     compileNode = beforeTemplateCompileNode;
8608                     $compileNode.html(content);
8609                   }
8610
8611                   directives.unshift(derivedSyncDirective);
8612
8613                   afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
8614                       childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
8615                       previousCompileContext);
8616                   forEach($rootElement, function(node, i) {
8617                     if (node == compileNode) {
8618                       $rootElement[i] = $compileNode[0];
8619                     }
8620                   });
8621                   afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
8622
8623                   while (linkQueue.length) {
8624                     var scope = linkQueue.shift(),
8625                         beforeTemplateLinkNode = linkQueue.shift(),
8626                         linkRootElement = linkQueue.shift(),
8627                         boundTranscludeFn = linkQueue.shift(),
8628                         linkNode = $compileNode[0];
8629
8630                     if (scope.$$destroyed) continue;
8631
8632                     if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
8633                       var oldClasses = beforeTemplateLinkNode.className;
8634
8635                       if (!(previousCompileContext.hasElementTranscludeDirective &&
8636                           origAsyncDirective.replace)) {
8637                         // it was cloned therefore we have to clone as well.
8638                         linkNode = jqLiteClone(compileNode);
8639                       }
8640                       replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
8641
8642                       // Copy in CSS classes from original node
8643                       safeAddClass(jqLite(linkNode), oldClasses);
8644                     }
8645                     if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8646                       childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8647                     } else {
8648                       childBoundTranscludeFn = boundTranscludeFn;
8649                     }
8650                     afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
8651                       childBoundTranscludeFn);
8652                   }
8653                   linkQueue = null;
8654                 });
8655
8656               return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
8657                 var childBoundTranscludeFn = boundTranscludeFn;
8658                 if (scope.$$destroyed) return;
8659                 if (linkQueue) {
8660                   linkQueue.push(scope,
8661                                  node,
8662                                  rootElement,
8663                                  childBoundTranscludeFn);
8664                 } else {
8665                   if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8666                     childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8667                   }
8668                   afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
8669                 }
8670               };
8671             }
8672
8673
8674             /**
8675              * Sorting function for bound directives.
8676              */
8677             function byPriority(a, b) {
8678               var diff = b.priority - a.priority;
8679               if (diff !== 0) return diff;
8680               if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
8681               return a.index - b.index;
8682             }
8683
8684             function assertNoDuplicate(what, previousDirective, directive, element) {
8685
8686               function wrapModuleNameIfDefined(moduleName) {
8687                 return moduleName ?
8688                   (' (module: ' + moduleName + ')') :
8689                   '';
8690               }
8691
8692               if (previousDirective) {
8693                 throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
8694                     previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
8695                     directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
8696               }
8697             }
8698
8699
8700             function addTextInterpolateDirective(directives, text) {
8701               var interpolateFn = $interpolate(text, true);
8702               if (interpolateFn) {
8703                 directives.push({
8704                   priority: 0,
8705                   compile: function textInterpolateCompileFn(templateNode) {
8706                     var templateNodeParent = templateNode.parent(),
8707                         hasCompileParent = !!templateNodeParent.length;
8708
8709                     // When transcluding a template that has bindings in the root
8710                     // we don't have a parent and thus need to add the class during linking fn.
8711                     if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
8712
8713                     return function textInterpolateLinkFn(scope, node) {
8714                       var parent = node.parent();
8715                       if (!hasCompileParent) compile.$$addBindingClass(parent);
8716                       compile.$$addBindingInfo(parent, interpolateFn.expressions);
8717                       scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
8718                         node[0].nodeValue = value;
8719                       });
8720                     };
8721                   }
8722                 });
8723               }
8724             }
8725
8726
8727             function wrapTemplate(type, template) {
8728               type = lowercase(type || 'html');
8729               switch (type) {
8730               case 'svg':
8731               case 'math':
8732                 var wrapper = document.createElement('div');
8733                 wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
8734                 return wrapper.childNodes[0].childNodes;
8735               default:
8736                 return template;
8737               }
8738             }
8739
8740
8741             function getTrustedContext(node, attrNormalizedName) {
8742               if (attrNormalizedName == "srcdoc") {
8743                 return $sce.HTML;
8744               }
8745               var tag = nodeName_(node);
8746               // maction[xlink:href] can source SVG.  It's not limited to <maction>.
8747               if (attrNormalizedName == "xlinkHref" ||
8748                   (tag == "form" && attrNormalizedName == "action") ||
8749                   (tag != "img" && (attrNormalizedName == "src" ||
8750                                     attrNormalizedName == "ngSrc"))) {
8751                 return $sce.RESOURCE_URL;
8752               }
8753             }
8754
8755
8756             function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
8757               var trustedContext = getTrustedContext(node, name);
8758               allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
8759
8760               var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
8761
8762               // no interpolation found -> ignore
8763               if (!interpolateFn) return;
8764
8765
8766               if (name === "multiple" && nodeName_(node) === "select") {
8767                 throw $compileMinErr("selmulti",
8768                     "Binding to the 'multiple' attribute is not supported. Element: {0}",
8769                     startingTag(node));
8770               }
8771
8772               directives.push({
8773                 priority: 100,
8774                 compile: function() {
8775                     return {
8776                       pre: function attrInterpolatePreLinkFn(scope, element, attr) {
8777                         var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
8778
8779                         if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
8780                           throw $compileMinErr('nodomevents',
8781                               "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
8782                                   "ng- versions (such as ng-click instead of onclick) instead.");
8783                         }
8784
8785                         // If the attribute has changed since last $interpolate()ed
8786                         var newValue = attr[name];
8787                         if (newValue !== value) {
8788                           // we need to interpolate again since the attribute value has been updated
8789                           // (e.g. by another directive's compile function)
8790                           // ensure unset/empty values make interpolateFn falsy
8791                           interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
8792                           value = newValue;
8793                         }
8794
8795                         // if attribute was updated so that there is no interpolation going on we don't want to
8796                         // register any observers
8797                         if (!interpolateFn) return;
8798
8799                         // initialize attr object so that it's ready in case we need the value for isolate
8800                         // scope initialization, otherwise the value would not be available from isolate
8801                         // directive's linking fn during linking phase
8802                         attr[name] = interpolateFn(scope);
8803
8804                         ($$observers[name] || ($$observers[name] = [])).$$inter = true;
8805                         (attr.$$observers && attr.$$observers[name].$$scope || scope).
8806                           $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
8807                             //special case for class attribute addition + removal
8808                             //so that class changes can tap into the animation
8809                             //hooks provided by the $animate service. Be sure to
8810                             //skip animations when the first digest occurs (when
8811                             //both the new and the old values are the same) since
8812                             //the CSS classes are the non-interpolated values
8813                             if (name === 'class' && newValue != oldValue) {
8814                               attr.$updateClass(newValue, oldValue);
8815                             } else {
8816                               attr.$set(name, newValue);
8817                             }
8818                           });
8819                       }
8820                     };
8821                   }
8822               });
8823             }
8824
8825
8826             /**
8827              * This is a special jqLite.replaceWith, which can replace items which
8828              * have no parents, provided that the containing jqLite collection is provided.
8829              *
8830              * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
8831              *                               in the root of the tree.
8832              * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
8833              *                                  the shell, but replace its DOM node reference.
8834              * @param {Node} newNode The new DOM node.
8835              */
8836             function replaceWith($rootElement, elementsToRemove, newNode) {
8837               var firstElementToRemove = elementsToRemove[0],
8838                   removeCount = elementsToRemove.length,
8839                   parent = firstElementToRemove.parentNode,
8840                   i, ii;
8841
8842               if ($rootElement) {
8843                 for (i = 0, ii = $rootElement.length; i < ii; i++) {
8844                   if ($rootElement[i] == firstElementToRemove) {
8845                     $rootElement[i++] = newNode;
8846                     for (var j = i, j2 = j + removeCount - 1,
8847                              jj = $rootElement.length;
8848                          j < jj; j++, j2++) {
8849                       if (j2 < jj) {
8850                         $rootElement[j] = $rootElement[j2];
8851                       } else {
8852                         delete $rootElement[j];
8853                       }
8854                     }
8855                     $rootElement.length -= removeCount - 1;
8856
8857                     // If the replaced element is also the jQuery .context then replace it
8858                     // .context is a deprecated jQuery api, so we should set it only when jQuery set it
8859                     // http://api.jquery.com/context/
8860                     if ($rootElement.context === firstElementToRemove) {
8861                       $rootElement.context = newNode;
8862                     }
8863                     break;
8864                   }
8865                 }
8866               }
8867
8868               if (parent) {
8869                 parent.replaceChild(newNode, firstElementToRemove);
8870               }
8871
8872               // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
8873               var fragment = document.createDocumentFragment();
8874               fragment.appendChild(firstElementToRemove);
8875
8876               if (jqLite.hasData(firstElementToRemove)) {
8877                 // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8878                 // data here because there's no public interface in jQuery to do that and copying over
8879                 // event listeners (which is the main use of private data) wouldn't work anyway.
8880                 jqLite.data(newNode, jqLite.data(firstElementToRemove));
8881
8882                 // Remove data of the replaced element. We cannot just call .remove()
8883                 // on the element it since that would deallocate scope that is needed
8884                 // for the new node. Instead, remove the data "manually".
8885                 if (!jQuery) {
8886                   delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8887                 } else {
8888                   // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8889                   // the replaced element. The cleanData version monkey-patched by Angular would cause
8890                   // the scope to be trashed and we do need the very same scope to work with the new
8891                   // element. However, we cannot just cache the non-patched version and use it here as
8892                   // that would break if another library patches the method after Angular does (one
8893                   // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8894                   // skipped this one time.
8895                   skipDestroyOnNextJQueryCleanData = true;
8896                   jQuery.cleanData([firstElementToRemove]);
8897                 }
8898               }
8899
8900               for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8901                 var element = elementsToRemove[k];
8902                 jqLite(element).remove(); // must do this way to clean up expando
8903                 fragment.appendChild(element);
8904                 delete elementsToRemove[k];
8905               }
8906
8907               elementsToRemove[0] = newNode;
8908               elementsToRemove.length = 1;
8909             }
8910
8911
8912             function cloneAndAnnotateFn(fn, annotation) {
8913               return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
8914             }
8915
8916
8917             function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
8918               try {
8919                 linkFn(scope, $element, attrs, controllers, transcludeFn);
8920               } catch (e) {
8921                 $exceptionHandler(e, startingTag($element));
8922               }
8923             }
8924
8925
8926             // Set up $watches for isolate scope and controller bindings. This process
8927             // only occurs for isolate scopes and new scopes with controllerAs.
8928             function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
8929               var removeWatchCollection = [];
8930               forEach(bindings, function(definition, scopeName) {
8931                 var attrName = definition.attrName,
8932                 optional = definition.optional,
8933                 mode = definition.mode, // @, =, or &
8934                 lastValue,
8935                 parentGet, parentSet, compare;
8936
8937                 switch (mode) {
8938
8939                   case '@':
8940                     if (!optional && !hasOwnProperty.call(attrs, attrName)) {
8941                       destination[scopeName] = attrs[attrName] = void 0;
8942                     }
8943                     attrs.$observe(attrName, function(value) {
8944                       if (isString(value)) {
8945                         destination[scopeName] = value;
8946                       }
8947                     });
8948                     attrs.$$observers[attrName].$$scope = scope;
8949                     if (isString(attrs[attrName])) {
8950                       // If the attribute has been provided then we trigger an interpolation to ensure
8951                       // the value is there for use in the link fn
8952                       destination[scopeName] = $interpolate(attrs[attrName])(scope);
8953                     }
8954                     break;
8955
8956                   case '=':
8957                     if (!hasOwnProperty.call(attrs, attrName)) {
8958                       if (optional) break;
8959                       attrs[attrName] = void 0;
8960                     }
8961                     if (optional && !attrs[attrName]) break;
8962
8963                     parentGet = $parse(attrs[attrName]);
8964                     if (parentGet.literal) {
8965                       compare = equals;
8966                     } else {
8967                       compare = function(a, b) { return a === b || (a !== a && b !== b); };
8968                     }
8969                     parentSet = parentGet.assign || function() {
8970                       // reset the change, or we will throw this exception on every $digest
8971                       lastValue = destination[scopeName] = parentGet(scope);
8972                       throw $compileMinErr('nonassign',
8973                           "Expression '{0}' used with directive '{1}' is non-assignable!",
8974                           attrs[attrName], directive.name);
8975                     };
8976                     lastValue = destination[scopeName] = parentGet(scope);
8977                     var parentValueWatch = function parentValueWatch(parentValue) {
8978                       if (!compare(parentValue, destination[scopeName])) {
8979                         // we are out of sync and need to copy
8980                         if (!compare(parentValue, lastValue)) {
8981                           // parent changed and it has precedence
8982                           destination[scopeName] = parentValue;
8983                         } else {
8984                           // if the parent can be assigned then do so
8985                           parentSet(scope, parentValue = destination[scopeName]);
8986                         }
8987                       }
8988                       return lastValue = parentValue;
8989                     };
8990                     parentValueWatch.$stateful = true;
8991                     var removeWatch;
8992                     if (definition.collection) {
8993                       removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
8994                     } else {
8995                       removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
8996                     }
8997                     removeWatchCollection.push(removeWatch);
8998                     break;
8999
9000                   case '&':
9001                     // Don't assign Object.prototype method to scope
9002                     parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
9003
9004                     // Don't assign noop to destination if expression is not valid
9005                     if (parentGet === noop && optional) break;
9006
9007                     destination[scopeName] = function(locals) {
9008                       return parentGet(scope, locals);
9009                     };
9010                     break;
9011                 }
9012               });
9013
9014               return removeWatchCollection.length && function removeWatches() {
9015                 for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
9016                   removeWatchCollection[i]();
9017                 }
9018               };
9019             }
9020           }];
9021         }
9022
9023         var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
9024         /**
9025          * Converts all accepted directives format into proper directive name.
9026          * @param name Name to normalize
9027          */
9028         function directiveNormalize(name) {
9029           return camelCase(name.replace(PREFIX_REGEXP, ''));
9030         }
9031
9032         /**
9033          * @ngdoc type
9034          * @name $compile.directive.Attributes
9035          *
9036          * @description
9037          * A shared object between directive compile / linking functions which contains normalized DOM
9038          * element attributes. The values reflect current binding state `{{ }}`. The normalization is
9039          * needed since all of these are treated as equivalent in Angular:
9040          *
9041          * ```
9042          *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
9043          * ```
9044          */
9045
9046         /**
9047          * @ngdoc property
9048          * @name $compile.directive.Attributes#$attr
9049          *
9050          * @description
9051          * A map of DOM element attribute names to the normalized name. This is
9052          * needed to do reverse lookup from normalized name back to actual name.
9053          */
9054
9055
9056         /**
9057          * @ngdoc method
9058          * @name $compile.directive.Attributes#$set
9059          * @kind function
9060          *
9061          * @description
9062          * Set DOM element attribute value.
9063          *
9064          *
9065          * @param {string} name Normalized element attribute name of the property to modify. The name is
9066          *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
9067          *          property to the original name.
9068          * @param {string} value Value to set the attribute to. The value can be an interpolated string.
9069          */
9070
9071
9072
9073         /**
9074          * Closure compiler type information
9075          */
9076
9077         function nodesetLinkingFn(
9078           /* angular.Scope */ scope,
9079           /* NodeList */ nodeList,
9080           /* Element */ rootElement,
9081           /* function(Function) */ boundTranscludeFn
9082         ) {}
9083
9084         function directiveLinkingFn(
9085           /* nodesetLinkingFn */ nodesetLinkingFn,
9086           /* angular.Scope */ scope,
9087           /* Node */ node,
9088           /* Element */ rootElement,
9089           /* function(Function) */ boundTranscludeFn
9090         ) {}
9091
9092         function tokenDifference(str1, str2) {
9093           var values = '',
9094               tokens1 = str1.split(/\s+/),
9095               tokens2 = str2.split(/\s+/);
9096
9097           outer:
9098           for (var i = 0; i < tokens1.length; i++) {
9099             var token = tokens1[i];
9100             for (var j = 0; j < tokens2.length; j++) {
9101               if (token == tokens2[j]) continue outer;
9102             }
9103             values += (values.length > 0 ? ' ' : '') + token;
9104           }
9105           return values;
9106         }
9107
9108         function removeComments(jqNodes) {
9109           jqNodes = jqLite(jqNodes);
9110           var i = jqNodes.length;
9111
9112           if (i <= 1) {
9113             return jqNodes;
9114           }
9115
9116           while (i--) {
9117             var node = jqNodes[i];
9118             if (node.nodeType === NODE_TYPE_COMMENT) {
9119               splice.call(jqNodes, i, 1);
9120             }
9121           }
9122           return jqNodes;
9123         }
9124
9125         var $controllerMinErr = minErr('$controller');
9126
9127
9128         var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
9129         function identifierForController(controller, ident) {
9130           if (ident && isString(ident)) return ident;
9131           if (isString(controller)) {
9132             var match = CNTRL_REG.exec(controller);
9133             if (match) return match[3];
9134           }
9135         }
9136
9137
9138         /**
9139          * @ngdoc provider
9140          * @name $controllerProvider
9141          * @description
9142          * The {@link ng.$controller $controller service} is used by Angular to create new
9143          * controllers.
9144          *
9145          * This provider allows controller registration via the
9146          * {@link ng.$controllerProvider#register register} method.
9147          */
9148         function $ControllerProvider() {
9149           var controllers = {},
9150               globals = false;
9151
9152           /**
9153            * @ngdoc method
9154            * @name $controllerProvider#register
9155            * @param {string|Object} name Controller name, or an object map of controllers where the keys are
9156            *    the names and the values are the constructors.
9157            * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
9158            *    annotations in the array notation).
9159            */
9160           this.register = function(name, constructor) {
9161             assertNotHasOwnProperty(name, 'controller');
9162             if (isObject(name)) {
9163               extend(controllers, name);
9164             } else {
9165               controllers[name] = constructor;
9166             }
9167           };
9168
9169           /**
9170            * @ngdoc method
9171            * @name $controllerProvider#allowGlobals
9172            * @description If called, allows `$controller` to find controller constructors on `window`
9173            */
9174           this.allowGlobals = function() {
9175             globals = true;
9176           };
9177
9178
9179           this.$get = ['$injector', '$window', function($injector, $window) {
9180
9181             /**
9182              * @ngdoc service
9183              * @name $controller
9184              * @requires $injector
9185              *
9186              * @param {Function|string} constructor If called with a function then it's considered to be the
9187              *    controller constructor function. Otherwise it's considered to be a string which is used
9188              *    to retrieve the controller constructor using the following steps:
9189              *
9190              *    * check if a controller with given name is registered via `$controllerProvider`
9191              *    * check if evaluating the string on the current scope returns a constructor
9192              *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
9193              *      `window` object (not recommended)
9194              *
9195              *    The string can use the `controller as property` syntax, where the controller instance is published
9196              *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
9197              *    to work correctly.
9198              *
9199              * @param {Object} locals Injection locals for Controller.
9200              * @return {Object} Instance of given controller.
9201              *
9202              * @description
9203              * `$controller` service is responsible for instantiating controllers.
9204              *
9205              * It's just a simple call to {@link auto.$injector $injector}, but extracted into
9206              * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
9207              */
9208             return function(expression, locals, later, ident) {
9209               // PRIVATE API:
9210               //   param `later` --- indicates that the controller's constructor is invoked at a later time.
9211               //                     If true, $controller will allocate the object with the correct
9212               //                     prototype chain, but will not invoke the controller until a returned
9213               //                     callback is invoked.
9214               //   param `ident` --- An optional label which overrides the label parsed from the controller
9215               //                     expression, if any.
9216               var instance, match, constructor, identifier;
9217               later = later === true;
9218               if (ident && isString(ident)) {
9219                 identifier = ident;
9220               }
9221
9222               if (isString(expression)) {
9223                 match = expression.match(CNTRL_REG);
9224                 if (!match) {
9225                   throw $controllerMinErr('ctrlfmt',
9226                     "Badly formed controller string '{0}'. " +
9227                     "Must match `__name__ as __id__` or `__name__`.", expression);
9228                 }
9229                 constructor = match[1],
9230                 identifier = identifier || match[3];
9231                 expression = controllers.hasOwnProperty(constructor)
9232                     ? controllers[constructor]
9233                     : getter(locals.$scope, constructor, true) ||
9234                         (globals ? getter($window, constructor, true) : undefined);
9235
9236                 assertArgFn(expression, constructor, true);
9237               }
9238
9239               if (later) {
9240                 // Instantiate controller later:
9241                 // This machinery is used to create an instance of the object before calling the
9242                 // controller's constructor itself.
9243                 //
9244                 // This allows properties to be added to the controller before the constructor is
9245                 // invoked. Primarily, this is used for isolate scope bindings in $compile.
9246                 //
9247                 // This feature is not intended for use by applications, and is thus not documented
9248                 // publicly.
9249                 // Object creation: http://jsperf.com/create-constructor/2
9250                 var controllerPrototype = (isArray(expression) ?
9251                   expression[expression.length - 1] : expression).prototype;
9252                 instance = Object.create(controllerPrototype || null);
9253
9254                 if (identifier) {
9255                   addIdentifier(locals, identifier, instance, constructor || expression.name);
9256                 }
9257
9258                 var instantiate;
9259                 return instantiate = extend(function() {
9260                   var result = $injector.invoke(expression, instance, locals, constructor);
9261                   if (result !== instance && (isObject(result) || isFunction(result))) {
9262                     instance = result;
9263                     if (identifier) {
9264                       // If result changed, re-assign controllerAs value to scope.
9265                       addIdentifier(locals, identifier, instance, constructor || expression.name);
9266                     }
9267                   }
9268                   return instance;
9269                 }, {
9270                   instance: instance,
9271                   identifier: identifier
9272                 });
9273               }
9274
9275               instance = $injector.instantiate(expression, locals, constructor);
9276
9277               if (identifier) {
9278                 addIdentifier(locals, identifier, instance, constructor || expression.name);
9279               }
9280
9281               return instance;
9282             };
9283
9284             function addIdentifier(locals, identifier, instance, name) {
9285               if (!(locals && isObject(locals.$scope))) {
9286                 throw minErr('$controller')('noscp',
9287                   "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
9288                   name, identifier);
9289               }
9290
9291               locals.$scope[identifier] = instance;
9292             }
9293           }];
9294         }
9295
9296         /**
9297          * @ngdoc service
9298          * @name $document
9299          * @requires $window
9300          *
9301          * @description
9302          * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
9303          *
9304          * @example
9305            <example module="documentExample">
9306              <file name="index.html">
9307                <div ng-controller="ExampleController">
9308                  <p>$document title: <b ng-bind="title"></b></p>
9309                  <p>window.document title: <b ng-bind="windowTitle"></b></p>
9310                </div>
9311              </file>
9312              <file name="script.js">
9313                angular.module('documentExample', [])
9314                  .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
9315                    $scope.title = $document[0].title;
9316                    $scope.windowTitle = angular.element(window.document)[0].title;
9317                  }]);
9318              </file>
9319            </example>
9320          */
9321         function $DocumentProvider() {
9322           this.$get = ['$window', function(window) {
9323             return jqLite(window.document);
9324           }];
9325         }
9326
9327         /**
9328          * @ngdoc service
9329          * @name $exceptionHandler
9330          * @requires ng.$log
9331          *
9332          * @description
9333          * Any uncaught exception in angular expressions is delegated to this service.
9334          * The default implementation simply delegates to `$log.error` which logs it into
9335          * the browser console.
9336          *
9337          * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
9338          * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
9339          *
9340          * ## Example:
9341          *
9342          * ```js
9343          *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
9344          *     return function(exception, cause) {
9345          *       exception.message += ' (caused by "' + cause + '")';
9346          *       throw exception;
9347          *     };
9348          *   });
9349          * ```
9350          *
9351          * This example will override the normal action of `$exceptionHandler`, to make angular
9352          * exceptions fail hard when they happen, instead of just logging to the console.
9353          *
9354          * <hr />
9355          * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
9356          * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
9357          * (unless executed during a digest).
9358          *
9359          * If you wish, you can manually delegate exceptions, e.g.
9360          * `try { ... } catch(e) { $exceptionHandler(e); }`
9361          *
9362          * @param {Error} exception Exception associated with the error.
9363          * @param {string=} cause optional information about the context in which
9364          *       the error was thrown.
9365          *
9366          */
9367         function $ExceptionHandlerProvider() {
9368           this.$get = ['$log', function($log) {
9369             return function(exception, cause) {
9370               $log.error.apply($log, arguments);
9371             };
9372           }];
9373         }
9374
9375         var $$ForceReflowProvider = function() {
9376           this.$get = ['$document', function($document) {
9377             return function(domNode) {
9378               //the line below will force the browser to perform a repaint so
9379               //that all the animated elements within the animation frame will
9380               //be properly updated and drawn on screen. This is required to
9381               //ensure that the preparation animation is properly flushed so that
9382               //the active state picks up from there. DO NOT REMOVE THIS LINE.
9383               //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
9384               //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
9385               //WILL TAKE YEARS AWAY FROM YOUR LIFE.
9386               if (domNode) {
9387                 if (!domNode.nodeType && domNode instanceof jqLite) {
9388                   domNode = domNode[0];
9389                 }
9390               } else {
9391                 domNode = $document[0].body;
9392               }
9393               return domNode.offsetWidth + 1;
9394             };
9395           }];
9396         };
9397
9398         var APPLICATION_JSON = 'application/json';
9399         var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
9400         var JSON_START = /^\[|^\{(?!\{)/;
9401         var JSON_ENDS = {
9402           '[': /]$/,
9403           '{': /}$/
9404         };
9405         var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
9406         var $httpMinErr = minErr('$http');
9407         var $httpMinErrLegacyFn = function(method) {
9408           return function() {
9409             throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
9410           };
9411         };
9412
9413         function serializeValue(v) {
9414           if (isObject(v)) {
9415             return isDate(v) ? v.toISOString() : toJson(v);
9416           }
9417           return v;
9418         }
9419
9420
9421         function $HttpParamSerializerProvider() {
9422           /**
9423            * @ngdoc service
9424            * @name $httpParamSerializer
9425            * @description
9426            *
9427            * Default {@link $http `$http`} params serializer that converts objects to strings
9428            * according to the following rules:
9429            *
9430            * * `{'foo': 'bar'}` results in `foo=bar`
9431            * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
9432            * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
9433            * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
9434            *
9435            * Note that serializer will sort the request parameters alphabetically.
9436            * */
9437
9438           this.$get = function() {
9439             return function ngParamSerializer(params) {
9440               if (!params) return '';
9441               var parts = [];
9442               forEachSorted(params, function(value, key) {
9443                 if (value === null || isUndefined(value)) return;
9444                 if (isArray(value)) {
9445                   forEach(value, function(v, k) {
9446                     parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
9447                   });
9448                 } else {
9449                   parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
9450                 }
9451               });
9452
9453               return parts.join('&');
9454             };
9455           };
9456         }
9457
9458         function $HttpParamSerializerJQLikeProvider() {
9459           /**
9460            * @ngdoc service
9461            * @name $httpParamSerializerJQLike
9462            * @description
9463            *
9464            * Alternative {@link $http `$http`} params serializer that follows
9465            * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
9466            * The serializer will also sort the params alphabetically.
9467            *
9468            * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
9469            *
9470            * ```js
9471            * $http({
9472            *   url: myUrl,
9473            *   method: 'GET',
9474            *   params: myParams,
9475            *   paramSerializer: '$httpParamSerializerJQLike'
9476            * });
9477            * ```
9478            *
9479            * It is also possible to set it as the default `paramSerializer` in the
9480            * {@link $httpProvider#defaults `$httpProvider`}.
9481            *
9482            * Additionally, you can inject the serializer and use it explicitly, for example to serialize
9483            * form data for submission:
9484            *
9485            * ```js
9486            * .controller(function($http, $httpParamSerializerJQLike) {
9487            *   //...
9488            *
9489            *   $http({
9490            *     url: myUrl,
9491            *     method: 'POST',
9492            *     data: $httpParamSerializerJQLike(myData),
9493            *     headers: {
9494            *       'Content-Type': 'application/x-www-form-urlencoded'
9495            *     }
9496            *   });
9497            *
9498            * });
9499            * ```
9500            *
9501            * */
9502           this.$get = function() {
9503             return function jQueryLikeParamSerializer(params) {
9504               if (!params) return '';
9505               var parts = [];
9506               serialize(params, '', true);
9507               return parts.join('&');
9508
9509               function serialize(toSerialize, prefix, topLevel) {
9510                 if (toSerialize === null || isUndefined(toSerialize)) return;
9511                 if (isArray(toSerialize)) {
9512                   forEach(toSerialize, function(value, index) {
9513                     serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
9514                   });
9515                 } else if (isObject(toSerialize) && !isDate(toSerialize)) {
9516                   forEachSorted(toSerialize, function(value, key) {
9517                     serialize(value, prefix +
9518                         (topLevel ? '' : '[') +
9519                         key +
9520                         (topLevel ? '' : ']'));
9521                   });
9522                 } else {
9523                   parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
9524                 }
9525               }
9526             };
9527           };
9528         }
9529
9530         function defaultHttpResponseTransform(data, headers) {
9531           if (isString(data)) {
9532             // Strip json vulnerability protection prefix and trim whitespace
9533             var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
9534
9535             if (tempData) {
9536               var contentType = headers('Content-Type');
9537               if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
9538                 data = fromJson(tempData);
9539               }
9540             }
9541           }
9542
9543           return data;
9544         }
9545
9546         function isJsonLike(str) {
9547             var jsonStart = str.match(JSON_START);
9548             return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
9549         }
9550
9551         /**
9552          * Parse headers into key value object
9553          *
9554          * @param {string} headers Raw headers as a string
9555          * @returns {Object} Parsed headers as key value object
9556          */
9557         function parseHeaders(headers) {
9558           var parsed = createMap(), i;
9559
9560           function fillInParsed(key, val) {
9561             if (key) {
9562               parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
9563             }
9564           }
9565
9566           if (isString(headers)) {
9567             forEach(headers.split('\n'), function(line) {
9568               i = line.indexOf(':');
9569               fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
9570             });
9571           } else if (isObject(headers)) {
9572             forEach(headers, function(headerVal, headerKey) {
9573               fillInParsed(lowercase(headerKey), trim(headerVal));
9574             });
9575           }
9576
9577           return parsed;
9578         }
9579
9580
9581         /**
9582          * Returns a function that provides access to parsed headers.
9583          *
9584          * Headers are lazy parsed when first requested.
9585          * @see parseHeaders
9586          *
9587          * @param {(string|Object)} headers Headers to provide access to.
9588          * @returns {function(string=)} Returns a getter function which if called with:
9589          *
9590          *   - if called with single an argument returns a single header value or null
9591          *   - if called with no arguments returns an object containing all headers.
9592          */
9593         function headersGetter(headers) {
9594           var headersObj;
9595
9596           return function(name) {
9597             if (!headersObj) headersObj =  parseHeaders(headers);
9598
9599             if (name) {
9600               var value = headersObj[lowercase(name)];
9601               if (value === void 0) {
9602                 value = null;
9603               }
9604               return value;
9605             }
9606
9607             return headersObj;
9608           };
9609         }
9610
9611
9612         /**
9613          * Chain all given functions
9614          *
9615          * This function is used for both request and response transforming
9616          *
9617          * @param {*} data Data to transform.
9618          * @param {function(string=)} headers HTTP headers getter fn.
9619          * @param {number} status HTTP status code of the response.
9620          * @param {(Function|Array.<Function>)} fns Function or an array of functions.
9621          * @returns {*} Transformed data.
9622          */
9623         function transformData(data, headers, status, fns) {
9624           if (isFunction(fns)) {
9625             return fns(data, headers, status);
9626           }
9627
9628           forEach(fns, function(fn) {
9629             data = fn(data, headers, status);
9630           });
9631
9632           return data;
9633         }
9634
9635
9636         function isSuccess(status) {
9637           return 200 <= status && status < 300;
9638         }
9639
9640
9641         /**
9642          * @ngdoc provider
9643          * @name $httpProvider
9644          * @description
9645          * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
9646          * */
9647         function $HttpProvider() {
9648           /**
9649            * @ngdoc property
9650            * @name $httpProvider#defaults
9651            * @description
9652            *
9653            * Object containing default values for all {@link ng.$http $http} requests.
9654            *
9655            * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
9656            * that will provide the cache for all requests who set their `cache` property to `true`.
9657            * If you set the `defaults.cache = false` then only requests that specify their own custom
9658            * cache object will be cached. See {@link $http#caching $http Caching} for more information.
9659            *
9660            * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
9661            * Defaults value is `'XSRF-TOKEN'`.
9662            *
9663            * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
9664            * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
9665            *
9666            * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
9667            * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
9668            * setting default headers.
9669            *     - **`defaults.headers.common`**
9670            *     - **`defaults.headers.post`**
9671            *     - **`defaults.headers.put`**
9672            *     - **`defaults.headers.patch`**
9673            *
9674            *
9675            * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
9676            *  used to the prepare string representation of request parameters (specified as an object).
9677            *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
9678            *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
9679            *
9680            **/
9681           var defaults = this.defaults = {
9682             // transform incoming response data
9683             transformResponse: [defaultHttpResponseTransform],
9684
9685             // transform outgoing request data
9686             transformRequest: [function(d) {
9687               return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
9688             }],
9689
9690             // default headers
9691             headers: {
9692               common: {
9693                 'Accept': 'application/json, text/plain, */*'
9694               },
9695               post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9696               put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9697               patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
9698             },
9699
9700             xsrfCookieName: 'XSRF-TOKEN',
9701             xsrfHeaderName: 'X-XSRF-TOKEN',
9702
9703             paramSerializer: '$httpParamSerializer'
9704           };
9705
9706           var useApplyAsync = false;
9707           /**
9708            * @ngdoc method
9709            * @name $httpProvider#useApplyAsync
9710            * @description
9711            *
9712            * Configure $http service to combine processing of multiple http responses received at around
9713            * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
9714            * significant performance improvement for bigger applications that make many HTTP requests
9715            * concurrently (common during application bootstrap).
9716            *
9717            * Defaults to false. If no value is specified, returns the current configured value.
9718            *
9719            * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
9720            *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
9721            *    to load and share the same digest cycle.
9722            *
9723            * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9724            *    otherwise, returns the current configured value.
9725            **/
9726           this.useApplyAsync = function(value) {
9727             if (isDefined(value)) {
9728               useApplyAsync = !!value;
9729               return this;
9730             }
9731             return useApplyAsync;
9732           };
9733
9734           var useLegacyPromise = true;
9735           /**
9736            * @ngdoc method
9737            * @name $httpProvider#useLegacyPromiseExtensions
9738            * @description
9739            *
9740            * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
9741            * This should be used to make sure that applications work without these methods.
9742            *
9743            * Defaults to true. If no value is specified, returns the current configured value.
9744            *
9745            * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
9746            *
9747            * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9748            *    otherwise, returns the current configured value.
9749            **/
9750           this.useLegacyPromiseExtensions = function(value) {
9751             if (isDefined(value)) {
9752               useLegacyPromise = !!value;
9753               return this;
9754             }
9755             return useLegacyPromise;
9756           };
9757
9758           /**
9759            * @ngdoc property
9760            * @name $httpProvider#interceptors
9761            * @description
9762            *
9763            * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
9764            * pre-processing of request or postprocessing of responses.
9765            *
9766            * These service factories are ordered by request, i.e. they are applied in the same order as the
9767            * array, on request, but reverse order, on response.
9768            *
9769            * {@link ng.$http#interceptors Interceptors detailed info}
9770            **/
9771           var interceptorFactories = this.interceptors = [];
9772
9773           this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
9774               function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
9775
9776             var defaultCache = $cacheFactory('$http');
9777
9778             /**
9779              * Make sure that default param serializer is exposed as a function
9780              */
9781             defaults.paramSerializer = isString(defaults.paramSerializer) ?
9782               $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
9783
9784             /**
9785              * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
9786              * The reversal is needed so that we can build up the interception chain around the
9787              * server request.
9788              */
9789             var reversedInterceptors = [];
9790
9791             forEach(interceptorFactories, function(interceptorFactory) {
9792               reversedInterceptors.unshift(isString(interceptorFactory)
9793                   ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
9794             });
9795
9796             /**
9797              * @ngdoc service
9798              * @kind function
9799              * @name $http
9800              * @requires ng.$httpBackend
9801              * @requires $cacheFactory
9802              * @requires $rootScope
9803              * @requires $q
9804              * @requires $injector
9805              *
9806              * @description
9807              * The `$http` service is a core Angular service that facilitates communication with the remote
9808              * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
9809              * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
9810              *
9811              * For unit testing applications that use `$http` service, see
9812              * {@link ngMock.$httpBackend $httpBackend mock}.
9813              *
9814              * For a higher level of abstraction, please check out the {@link ngResource.$resource
9815              * $resource} service.
9816              *
9817              * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
9818              * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
9819              * it is important to familiarize yourself with these APIs and the guarantees they provide.
9820              *
9821              *
9822              * ## General usage
9823              * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
9824              * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
9825              *
9826              * ```js
9827              *   // Simple GET request example:
9828              *   $http({
9829              *     method: 'GET',
9830              *     url: '/someUrl'
9831              *   }).then(function successCallback(response) {
9832              *       // this callback will be called asynchronously
9833              *       // when the response is available
9834              *     }, function errorCallback(response) {
9835              *       // called asynchronously if an error occurs
9836              *       // or server returns response with an error status.
9837              *     });
9838              * ```
9839              *
9840              * The response object has these properties:
9841              *
9842              *   - **data** – `{string|Object}` – The response body transformed with the transform
9843              *     functions.
9844              *   - **status** – `{number}` – HTTP status code of the response.
9845              *   - **headers** – `{function([headerName])}` – Header getter function.
9846              *   - **config** – `{Object}` – The configuration object that was used to generate the request.
9847              *   - **statusText** – `{string}` – HTTP status text of the response.
9848              *
9849              * A response status code between 200 and 299 is considered a success status and
9850              * will result in the success callback being called. Note that if the response is a redirect,
9851              * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
9852              * called for such responses.
9853              *
9854              *
9855              * ## Shortcut methods
9856              *
9857              * Shortcut methods are also available. All shortcut methods require passing in the URL, and
9858              * request data must be passed in for POST/PUT requests. An optional config can be passed as the
9859              * last argument.
9860              *
9861              * ```js
9862              *   $http.get('/someUrl', config).then(successCallback, errorCallback);
9863              *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
9864              * ```
9865              *
9866              * Complete list of shortcut methods:
9867              *
9868              * - {@link ng.$http#get $http.get}
9869              * - {@link ng.$http#head $http.head}
9870              * - {@link ng.$http#post $http.post}
9871              * - {@link ng.$http#put $http.put}
9872              * - {@link ng.$http#delete $http.delete}
9873              * - {@link ng.$http#jsonp $http.jsonp}
9874              * - {@link ng.$http#patch $http.patch}
9875              *
9876              *
9877              * ## Writing Unit Tests that use $http
9878              * When unit testing (using {@link ngMock ngMock}), it is necessary to call
9879              * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
9880              * request using trained responses.
9881              *
9882              * ```
9883              * $httpBackend.expectGET(...);
9884              * $http.get(...);
9885              * $httpBackend.flush();
9886              * ```
9887              *
9888              * ## Deprecation Notice
9889              * <div class="alert alert-danger">
9890              *   The `$http` legacy promise methods `success` and `error` have been deprecated.
9891              *   Use the standard `then` method instead.
9892              *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
9893              *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
9894              * </div>
9895              *
9896              * ## Setting HTTP Headers
9897              *
9898              * The $http service will automatically add certain HTTP headers to all requests. These defaults
9899              * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
9900              * object, which currently contains this default configuration:
9901              *
9902              * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
9903              *   - `Accept: application/json, text/plain, * / *`
9904              * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
9905              *   - `Content-Type: application/json`
9906              * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
9907              *   - `Content-Type: application/json`
9908              *
9909              * To add or overwrite these defaults, simply add or remove a property from these configuration
9910              * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
9911              * with the lowercased HTTP method name as the key, e.g.
9912              * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
9913              *
9914              * The defaults can also be set at runtime via the `$http.defaults` object in the same
9915              * fashion. For example:
9916              *
9917              * ```
9918              * module.run(function($http) {
9919              *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
9920              * });
9921              * ```
9922              *
9923              * In addition, you can supply a `headers` property in the config object passed when
9924              * calling `$http(config)`, which overrides the defaults without changing them globally.
9925              *
9926              * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
9927              * Use the `headers` property, setting the desired header to `undefined`. For example:
9928              *
9929              * ```js
9930              * var req = {
9931              *  method: 'POST',
9932              *  url: 'http://example.com',
9933              *  headers: {
9934              *    'Content-Type': undefined
9935              *  },
9936              *  data: { test: 'test' }
9937              * }
9938              *
9939              * $http(req).then(function(){...}, function(){...});
9940              * ```
9941              *
9942              * ## Transforming Requests and Responses
9943              *
9944              * Both requests and responses can be transformed using transformation functions: `transformRequest`
9945              * and `transformResponse`. These properties can be a single function that returns
9946              * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
9947              * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
9948              *
9949              * ### Default Transformations
9950              *
9951              * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
9952              * `defaults.transformResponse` properties. If a request does not provide its own transformations
9953              * then these will be applied.
9954              *
9955              * You can augment or replace the default transformations by modifying these properties by adding to or
9956              * replacing the array.
9957              *
9958              * Angular provides the following default transformations:
9959              *
9960              * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
9961              *
9962              * - If the `data` property of the request configuration object contains an object, serialize it
9963              *   into JSON format.
9964              *
9965              * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
9966              *
9967              *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
9968              *  - If JSON response is detected, deserialize it using a JSON parser.
9969              *
9970              *
9971              * ### Overriding the Default Transformations Per Request
9972              *
9973              * If you wish override the request/response transformations only for a single request then provide
9974              * `transformRequest` and/or `transformResponse` properties on the configuration object passed
9975              * into `$http`.
9976              *
9977              * Note that if you provide these properties on the config object the default transformations will be
9978              * overwritten. If you wish to augment the default transformations then you must include them in your
9979              * local transformation array.
9980              *
9981              * The following code demonstrates adding a new response transformation to be run after the default response
9982              * transformations have been run.
9983              *
9984              * ```js
9985              * function appendTransform(defaults, transform) {
9986              *
9987              *   // We can't guarantee that the default transformation is an array
9988              *   defaults = angular.isArray(defaults) ? defaults : [defaults];
9989              *
9990              *   // Append the new transformation to the defaults
9991              *   return defaults.concat(transform);
9992              * }
9993              *
9994              * $http({
9995              *   url: '...',
9996              *   method: 'GET',
9997              *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
9998              *     return doTransform(value);
9999              *   })
10000              * });
10001              * ```
10002              *
10003              *
10004              * ## Caching
10005              *
10006              * To enable caching, set the request configuration `cache` property to `true` (to use default
10007              * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
10008              * When the cache is enabled, `$http` stores the response from the server in the specified
10009              * cache. The next time the same request is made, the response is served from the cache without
10010              * sending a request to the server.
10011              *
10012              * Note that even if the response is served from cache, delivery of the data is asynchronous in
10013              * the same way that real requests are.
10014              *
10015              * If there are multiple GET requests for the same URL that should be cached using the same
10016              * cache, but the cache is not populated yet, only one request to the server will be made and
10017              * the remaining requests will be fulfilled using the response from the first request.
10018              *
10019              * You can change the default cache to a new object (built with
10020              * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
10021              * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
10022              * their `cache` property to `true` will now use this cache object.
10023              *
10024              * If you set the default cache to `false` then only requests that specify their own custom
10025              * cache object will be cached.
10026              *
10027              * ## Interceptors
10028              *
10029              * Before you start creating interceptors, be sure to understand the
10030              * {@link ng.$q $q and deferred/promise APIs}.
10031              *
10032              * For purposes of global error handling, authentication, or any kind of synchronous or
10033              * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
10034              * able to intercept requests before they are handed to the server and
10035              * responses before they are handed over to the application code that
10036              * initiated these requests. The interceptors leverage the {@link ng.$q
10037              * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
10038              *
10039              * The interceptors are service factories that are registered with the `$httpProvider` by
10040              * adding them to the `$httpProvider.interceptors` array. The factory is called and
10041              * injected with dependencies (if specified) and returns the interceptor.
10042              *
10043              * There are two kinds of interceptors (and two kinds of rejection interceptors):
10044              *
10045              *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
10046              *     modify the `config` object or create a new one. The function needs to return the `config`
10047              *     object directly, or a promise containing the `config` or a new `config` object.
10048              *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
10049              *     resolved with a rejection.
10050              *   * `response`: interceptors get called with http `response` object. The function is free to
10051              *     modify the `response` object or create a new one. The function needs to return the `response`
10052              *     object directly, or as a promise containing the `response` or a new `response` object.
10053              *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
10054              *     resolved with a rejection.
10055              *
10056              *
10057              * ```js
10058              *   // register the interceptor as a service
10059              *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
10060              *     return {
10061              *       // optional method
10062              *       'request': function(config) {
10063              *         // do something on success
10064              *         return config;
10065              *       },
10066              *
10067              *       // optional method
10068              *      'requestError': function(rejection) {
10069              *         // do something on error
10070              *         if (canRecover(rejection)) {
10071              *           return responseOrNewPromise
10072              *         }
10073              *         return $q.reject(rejection);
10074              *       },
10075              *
10076              *
10077              *
10078              *       // optional method
10079              *       'response': function(response) {
10080              *         // do something on success
10081              *         return response;
10082              *       },
10083              *
10084              *       // optional method
10085              *      'responseError': function(rejection) {
10086              *         // do something on error
10087              *         if (canRecover(rejection)) {
10088              *           return responseOrNewPromise
10089              *         }
10090              *         return $q.reject(rejection);
10091              *       }
10092              *     };
10093              *   });
10094              *
10095              *   $httpProvider.interceptors.push('myHttpInterceptor');
10096              *
10097              *
10098              *   // alternatively, register the interceptor via an anonymous factory
10099              *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
10100              *     return {
10101              *      'request': function(config) {
10102              *          // same as above
10103              *       },
10104              *
10105              *       'response': function(response) {
10106              *          // same as above
10107              *       }
10108              *     };
10109              *   });
10110              * ```
10111              *
10112              * ## Security Considerations
10113              *
10114              * When designing web applications, consider security threats from:
10115              *
10116              * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
10117              * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
10118              *
10119              * Both server and the client must cooperate in order to eliminate these threats. Angular comes
10120              * pre-configured with strategies that address these issues, but for this to work backend server
10121              * cooperation is required.
10122              *
10123              * ### JSON Vulnerability Protection
10124              *
10125              * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
10126              * allows third party website to turn your JSON resource URL into
10127              * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
10128              * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
10129              * Angular will automatically strip the prefix before processing it as JSON.
10130              *
10131              * For example if your server needs to return:
10132              * ```js
10133              * ['one','two']
10134              * ```
10135              *
10136              * which is vulnerable to attack, your server can return:
10137              * ```js
10138              * )]}',
10139              * ['one','two']
10140              * ```
10141              *
10142              * Angular will strip the prefix, before processing the JSON.
10143              *
10144              *
10145              * ### Cross Site Request Forgery (XSRF) Protection
10146              *
10147              * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
10148              * an unauthorized site can gain your user's private data. Angular provides a mechanism
10149              * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
10150              * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
10151              * JavaScript that runs on your domain could read the cookie, your server can be assured that
10152              * the XHR came from JavaScript running on your domain. The header will not be set for
10153              * cross-domain requests.
10154              *
10155              * To take advantage of this, your server needs to set a token in a JavaScript readable session
10156              * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
10157              * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
10158              * that only JavaScript running on your domain could have sent the request. The token must be
10159              * unique for each user and must be verifiable by the server (to prevent the JavaScript from
10160              * making up its own tokens). We recommend that the token is a digest of your site's
10161              * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
10162              * for added security.
10163              *
10164              * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
10165              * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
10166              * or the per-request config object.
10167              *
10168              * In order to prevent collisions in environments where multiple Angular apps share the
10169              * same domain or subdomain, we recommend that each application uses unique cookie name.
10170              *
10171              * @param {object} config Object describing the request to be made and how it should be
10172              *    processed. The object has following properties:
10173              *
10174              *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
10175              *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
10176              *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
10177              *      with the `paramSerializer` and appended as GET parameters.
10178              *    - **data** – `{string|Object}` – Data to be sent as the request message data.
10179              *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
10180              *      HTTP headers to send to the server. If the return value of a function is null, the
10181              *      header will not be sent. Functions accept a config object as an argument.
10182              *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
10183              *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
10184              *    - **transformRequest** –
10185              *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
10186              *      transform function or an array of such functions. The transform function takes the http
10187              *      request body and headers and returns its transformed (typically serialized) version.
10188              *      See {@link ng.$http#overriding-the-default-transformations-per-request
10189              *      Overriding the Default Transformations}
10190              *    - **transformResponse** –
10191              *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
10192              *      transform function or an array of such functions. The transform function takes the http
10193              *      response body, headers and status and returns its transformed (typically deserialized) version.
10194              *      See {@link ng.$http#overriding-the-default-transformations-per-request
10195              *      Overriding the Default TransformationjqLiks}
10196              *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
10197              *      prepare the string representation of request parameters (specified as an object).
10198              *      If specified as string, it is interpreted as function registered with the
10199              *      {@link $injector $injector}, which means you can create your own serializer
10200              *      by registering it as a {@link auto.$provide#service service}.
10201              *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
10202              *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
10203              *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
10204              *      GET request, otherwise if a cache instance built with
10205              *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
10206              *      caching.
10207              *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
10208              *      that should abort the request when resolved.
10209              *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
10210              *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
10211              *      for more information.
10212              *    - **responseType** - `{string}` - see
10213              *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
10214              *
10215              * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
10216              *                        when the request succeeds or fails.
10217              *
10218              *
10219              * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
10220              *   requests. This is primarily meant to be used for debugging purposes.
10221              *
10222              *
10223              * @example
10224         <example module="httpExample">
10225         <file name="index.html">
10226           <div ng-controller="FetchController">
10227             <select ng-model="method" aria-label="Request method">
10228               <option>GET</option>
10229               <option>JSONP</option>
10230             </select>
10231             <input type="text" ng-model="url" size="80" aria-label="URL" />
10232             <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
10233             <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
10234             <button id="samplejsonpbtn"
10235               ng-click="updateModel('JSONP',
10236                             'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
10237               Sample JSONP
10238             </button>
10239             <button id="invalidjsonpbtn"
10240               ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
10241                 Invalid JSONP
10242               </button>
10243             <pre>http status code: {{status}}</pre>
10244             <pre>http response data: {{data}}</pre>
10245           </div>
10246         </file>
10247         <file name="script.js">
10248           angular.module('httpExample', [])
10249             .controller('FetchController', ['$scope', '$http', '$templateCache',
10250               function($scope, $http, $templateCache) {
10251                 $scope.method = 'GET';
10252                 $scope.url = 'http-hello.html';
10253
10254                 $scope.fetch = function() {
10255                   $scope.code = null;
10256                   $scope.response = null;
10257
10258                   $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
10259                     then(function(response) {
10260                       $scope.status = response.status;
10261                       $scope.data = response.data;
10262                     }, function(response) {
10263                       $scope.data = response.data || "Request failed";
10264                       $scope.status = response.status;
10265                   });
10266                 };
10267
10268                 $scope.updateModel = function(method, url) {
10269                   $scope.method = method;
10270                   $scope.url = url;
10271                 };
10272               }]);
10273         </file>
10274         <file name="http-hello.html">
10275           Hello, $http!
10276         </file>
10277         <file name="protractor.js" type="protractor">
10278           var status = element(by.binding('status'));
10279           var data = element(by.binding('data'));
10280           var fetchBtn = element(by.id('fetchbtn'));
10281           var sampleGetBtn = element(by.id('samplegetbtn'));
10282           var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
10283           var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
10284
10285           it('should make an xhr GET request', function() {
10286             sampleGetBtn.click();
10287             fetchBtn.click();
10288             expect(status.getText()).toMatch('200');
10289             expect(data.getText()).toMatch(/Hello, \$http!/);
10290           });
10291
10292         // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
10293         // it('should make a JSONP request to angularjs.org', function() {
10294         //   sampleJsonpBtn.click();
10295         //   fetchBtn.click();
10296         //   expect(status.getText()).toMatch('200');
10297         //   expect(data.getText()).toMatch(/Super Hero!/);
10298         // });
10299
10300           it('should make JSONP request to invalid URL and invoke the error handler',
10301               function() {
10302             invalidJsonpBtn.click();
10303             fetchBtn.click();
10304             expect(status.getText()).toMatch('0');
10305             expect(data.getText()).toMatch('Request failed');
10306           });
10307         </file>
10308         </example>
10309              */
10310             function $http(requestConfig) {
10311
10312               if (!angular.isObject(requestConfig)) {
10313                 throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
10314               }
10315
10316               var config = extend({
10317                 method: 'get',
10318                 transformRequest: defaults.transformRequest,
10319                 transformResponse: defaults.transformResponse,
10320                 paramSerializer: defaults.paramSerializer
10321               }, requestConfig);
10322
10323               config.headers = mergeHeaders(requestConfig);
10324               config.method = uppercase(config.method);
10325               config.paramSerializer = isString(config.paramSerializer) ?
10326                 $injector.get(config.paramSerializer) : config.paramSerializer;
10327
10328               var serverRequest = function(config) {
10329                 var headers = config.headers;
10330                 var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
10331
10332                 // strip content-type if data is undefined
10333                 if (isUndefined(reqData)) {
10334                   forEach(headers, function(value, header) {
10335                     if (lowercase(header) === 'content-type') {
10336                         delete headers[header];
10337                     }
10338                   });
10339                 }
10340
10341                 if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
10342                   config.withCredentials = defaults.withCredentials;
10343                 }
10344
10345                 // send request
10346                 return sendReq(config, reqData).then(transformResponse, transformResponse);
10347               };
10348
10349               var chain = [serverRequest, undefined];
10350               var promise = $q.when(config);
10351
10352               // apply interceptors
10353               forEach(reversedInterceptors, function(interceptor) {
10354                 if (interceptor.request || interceptor.requestError) {
10355                   chain.unshift(interceptor.request, interceptor.requestError);
10356                 }
10357                 if (interceptor.response || interceptor.responseError) {
10358                   chain.push(interceptor.response, interceptor.responseError);
10359                 }
10360               });
10361
10362               while (chain.length) {
10363                 var thenFn = chain.shift();
10364                 var rejectFn = chain.shift();
10365
10366                 promise = promise.then(thenFn, rejectFn);
10367               }
10368
10369               if (useLegacyPromise) {
10370                 promise.success = function(fn) {
10371                   assertArgFn(fn, 'fn');
10372
10373                   promise.then(function(response) {
10374                     fn(response.data, response.status, response.headers, config);
10375                   });
10376                   return promise;
10377                 };
10378
10379                 promise.error = function(fn) {
10380                   assertArgFn(fn, 'fn');
10381
10382                   promise.then(null, function(response) {
10383                     fn(response.data, response.status, response.headers, config);
10384                   });
10385                   return promise;
10386                 };
10387               } else {
10388                 promise.success = $httpMinErrLegacyFn('success');
10389                 promise.error = $httpMinErrLegacyFn('error');
10390               }
10391
10392               return promise;
10393
10394               function transformResponse(response) {
10395                 // make a copy since the response must be cacheable
10396                 var resp = extend({}, response);
10397                 resp.data = transformData(response.data, response.headers, response.status,
10398                                           config.transformResponse);
10399                 return (isSuccess(response.status))
10400                   ? resp
10401                   : $q.reject(resp);
10402               }
10403
10404               function executeHeaderFns(headers, config) {
10405                 var headerContent, processedHeaders = {};
10406
10407                 forEach(headers, function(headerFn, header) {
10408                   if (isFunction(headerFn)) {
10409                     headerContent = headerFn(config);
10410                     if (headerContent != null) {
10411                       processedHeaders[header] = headerContent;
10412                     }
10413                   } else {
10414                     processedHeaders[header] = headerFn;
10415                   }
10416                 });
10417
10418                 return processedHeaders;
10419               }
10420
10421               function mergeHeaders(config) {
10422                 var defHeaders = defaults.headers,
10423                     reqHeaders = extend({}, config.headers),
10424                     defHeaderName, lowercaseDefHeaderName, reqHeaderName;
10425
10426                 defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
10427
10428                 // using for-in instead of forEach to avoid unecessary iteration after header has been found
10429                 defaultHeadersIteration:
10430                 for (defHeaderName in defHeaders) {
10431                   lowercaseDefHeaderName = lowercase(defHeaderName);
10432
10433                   for (reqHeaderName in reqHeaders) {
10434                     if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
10435                       continue defaultHeadersIteration;
10436                     }
10437                   }
10438
10439                   reqHeaders[defHeaderName] = defHeaders[defHeaderName];
10440                 }
10441
10442                 // execute if header value is a function for merged headers
10443                 return executeHeaderFns(reqHeaders, shallowCopy(config));
10444               }
10445             }
10446
10447             $http.pendingRequests = [];
10448
10449             /**
10450              * @ngdoc method
10451              * @name $http#get
10452              *
10453              * @description
10454              * Shortcut method to perform `GET` request.
10455              *
10456              * @param {string} url Relative or absolute URL specifying the destination of the request
10457              * @param {Object=} config Optional configuration object
10458              * @returns {HttpPromise} Future object
10459              */
10460
10461             /**
10462              * @ngdoc method
10463              * @name $http#delete
10464              *
10465              * @description
10466              * Shortcut method to perform `DELETE` request.
10467              *
10468              * @param {string} url Relative or absolute URL specifying the destination of the request
10469              * @param {Object=} config Optional configuration object
10470              * @returns {HttpPromise} Future object
10471              */
10472
10473             /**
10474              * @ngdoc method
10475              * @name $http#head
10476              *
10477              * @description
10478              * Shortcut method to perform `HEAD` request.
10479              *
10480              * @param {string} url Relative or absolute URL specifying the destination of the request
10481              * @param {Object=} config Optional configuration object
10482              * @returns {HttpPromise} Future object
10483              */
10484
10485             /**
10486              * @ngdoc method
10487              * @name $http#jsonp
10488              *
10489              * @description
10490              * Shortcut method to perform `JSONP` request.
10491              *
10492              * @param {string} url Relative or absolute URL specifying the destination of the request.
10493              *                     The name of the callback should be the string `JSON_CALLBACK`.
10494              * @param {Object=} config Optional configuration object
10495              * @returns {HttpPromise} Future object
10496              */
10497             createShortMethods('get', 'delete', 'head', 'jsonp');
10498
10499             /**
10500              * @ngdoc method
10501              * @name $http#post
10502              *
10503              * @description
10504              * Shortcut method to perform `POST` request.
10505              *
10506              * @param {string} url Relative or absolute URL specifying the destination of the request
10507              * @param {*} data Request content
10508              * @param {Object=} config Optional configuration object
10509              * @returns {HttpPromise} Future object
10510              */
10511
10512             /**
10513              * @ngdoc method
10514              * @name $http#put
10515              *
10516              * @description
10517              * Shortcut method to perform `PUT` request.
10518              *
10519              * @param {string} url Relative or absolute URL specifying the destination of the request
10520              * @param {*} data Request content
10521              * @param {Object=} config Optional configuration object
10522              * @returns {HttpPromise} Future object
10523              */
10524
10525              /**
10526               * @ngdoc method
10527               * @name $http#patch
10528               *
10529               * @description
10530               * Shortcut method to perform `PATCH` request.
10531               *
10532               * @param {string} url Relative or absolute URL specifying the destination of the request
10533               * @param {*} data Request content
10534               * @param {Object=} config Optional configuration object
10535               * @returns {HttpPromise} Future object
10536               */
10537             createShortMethodsWithData('post', 'put', 'patch');
10538
10539                 /**
10540                  * @ngdoc property
10541                  * @name $http#defaults
10542                  *
10543                  * @description
10544                  * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
10545                  * default headers, withCredentials as well as request and response transformations.
10546                  *
10547                  * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
10548                  */
10549             $http.defaults = defaults;
10550
10551
10552             return $http;
10553
10554
10555             function createShortMethods(names) {
10556               forEach(arguments, function(name) {
10557                 $http[name] = function(url, config) {
10558                   return $http(extend({}, config || {}, {
10559                     method: name,
10560                     url: url
10561                   }));
10562                 };
10563               });
10564             }
10565
10566
10567             function createShortMethodsWithData(name) {
10568               forEach(arguments, function(name) {
10569                 $http[name] = function(url, data, config) {
10570                   return $http(extend({}, config || {}, {
10571                     method: name,
10572                     url: url,
10573                     data: data
10574                   }));
10575                 };
10576               });
10577             }
10578
10579
10580             /**
10581              * Makes the request.
10582              *
10583              * !!! ACCESSES CLOSURE VARS:
10584              * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
10585              */
10586             function sendReq(config, reqData) {
10587               var deferred = $q.defer(),
10588                   promise = deferred.promise,
10589                   cache,
10590                   cachedResp,
10591                   reqHeaders = config.headers,
10592                   url = buildUrl(config.url, config.paramSerializer(config.params));
10593
10594               $http.pendingRequests.push(config);
10595               promise.then(removePendingReq, removePendingReq);
10596
10597
10598               if ((config.cache || defaults.cache) && config.cache !== false &&
10599                   (config.method === 'GET' || config.method === 'JSONP')) {
10600                 cache = isObject(config.cache) ? config.cache
10601                       : isObject(defaults.cache) ? defaults.cache
10602                       : defaultCache;
10603               }
10604
10605               if (cache) {
10606                 cachedResp = cache.get(url);
10607                 if (isDefined(cachedResp)) {
10608                   if (isPromiseLike(cachedResp)) {
10609                     // cached request has already been sent, but there is no response yet
10610                     cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
10611                   } else {
10612                     // serving from cache
10613                     if (isArray(cachedResp)) {
10614                       resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
10615                     } else {
10616                       resolvePromise(cachedResp, 200, {}, 'OK');
10617                     }
10618                   }
10619                 } else {
10620                   // put the promise for the non-transformed response into cache as a placeholder
10621                   cache.put(url, promise);
10622                 }
10623               }
10624
10625
10626               // if we won't have the response in cache, set the xsrf headers and
10627               // send the request to the backend
10628               if (isUndefined(cachedResp)) {
10629                 var xsrfValue = urlIsSameOrigin(config.url)
10630                     ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
10631                     : undefined;
10632                 if (xsrfValue) {
10633                   reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
10634                 }
10635
10636                 $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
10637                     config.withCredentials, config.responseType);
10638               }
10639
10640               return promise;
10641
10642
10643               /**
10644                * Callback registered to $httpBackend():
10645                *  - caches the response if desired
10646                *  - resolves the raw $http promise
10647                *  - calls $apply
10648                */
10649               function done(status, response, headersString, statusText) {
10650                 if (cache) {
10651                   if (isSuccess(status)) {
10652                     cache.put(url, [status, response, parseHeaders(headersString), statusText]);
10653                   } else {
10654                     // remove promise from the cache
10655                     cache.remove(url);
10656                   }
10657                 }
10658
10659                 function resolveHttpPromise() {
10660                   resolvePromise(response, status, headersString, statusText);
10661                 }
10662
10663                 if (useApplyAsync) {
10664                   $rootScope.$applyAsync(resolveHttpPromise);
10665                 } else {
10666                   resolveHttpPromise();
10667                   if (!$rootScope.$$phase) $rootScope.$apply();
10668                 }
10669               }
10670
10671
10672               /**
10673                * Resolves the raw $http promise.
10674                */
10675               function resolvePromise(response, status, headers, statusText) {
10676                 //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
10677                 status = status >= -1 ? status : 0;
10678
10679                 (isSuccess(status) ? deferred.resolve : deferred.reject)({
10680                   data: response,
10681                   status: status,
10682                   headers: headersGetter(headers),
10683                   config: config,
10684                   statusText: statusText
10685                 });
10686               }
10687
10688               function resolvePromiseWithResult(result) {
10689                 resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
10690               }
10691
10692               function removePendingReq() {
10693                 var idx = $http.pendingRequests.indexOf(config);
10694                 if (idx !== -1) $http.pendingRequests.splice(idx, 1);
10695               }
10696             }
10697
10698
10699             function buildUrl(url, serializedParams) {
10700               if (serializedParams.length > 0) {
10701                 url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
10702               }
10703               return url;
10704             }
10705           }];
10706         }
10707
10708         /**
10709          * @ngdoc service
10710          * @name $xhrFactory
10711          *
10712          * @description
10713          * Factory function used to create XMLHttpRequest objects.
10714          *
10715          * Replace or decorate this service to create your own custom XMLHttpRequest objects.
10716          *
10717          * ```
10718          * angular.module('myApp', [])
10719          * .factory('$xhrFactory', function() {
10720          *   return function createXhr(method, url) {
10721          *     return new window.XMLHttpRequest({mozSystem: true});
10722          *   };
10723          * });
10724          * ```
10725          *
10726          * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
10727          * @param {string} url URL of the request.
10728          */
10729         function $xhrFactoryProvider() {
10730           this.$get = function() {
10731             return function createXhr() {
10732               return new window.XMLHttpRequest();
10733             };
10734           };
10735         }
10736
10737         /**
10738          * @ngdoc service
10739          * @name $httpBackend
10740          * @requires $window
10741          * @requires $document
10742          * @requires $xhrFactory
10743          *
10744          * @description
10745          * HTTP backend used by the {@link ng.$http service} that delegates to
10746          * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
10747          *
10748          * You should never need to use this service directly, instead use the higher-level abstractions:
10749          * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
10750          *
10751          * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
10752          * $httpBackend} which can be trained with responses.
10753          */
10754         function $HttpBackendProvider() {
10755           this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
10756             return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
10757           }];
10758         }
10759
10760         function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
10761           // TODO(vojta): fix the signature
10762           return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
10763             $browser.$$incOutstandingRequestCount();
10764             url = url || $browser.url();
10765
10766             if (lowercase(method) == 'jsonp') {
10767               var callbackId = '_' + (callbacks.counter++).toString(36);
10768               callbacks[callbackId] = function(data) {
10769                 callbacks[callbackId].data = data;
10770                 callbacks[callbackId].called = true;
10771               };
10772
10773               var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
10774                   callbackId, function(status, text) {
10775                 completeRequest(callback, status, callbacks[callbackId].data, "", text);
10776                 callbacks[callbackId] = noop;
10777               });
10778             } else {
10779
10780               var xhr = createXhr(method, url);
10781
10782               xhr.open(method, url, true);
10783               forEach(headers, function(value, key) {
10784                 if (isDefined(value)) {
10785                     xhr.setRequestHeader(key, value);
10786                 }
10787               });
10788
10789               xhr.onload = function requestLoaded() {
10790                 var statusText = xhr.statusText || '';
10791
10792                 // responseText is the old-school way of retrieving response (supported by IE9)
10793                 // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
10794                 var response = ('response' in xhr) ? xhr.response : xhr.responseText;
10795
10796                 // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
10797                 var status = xhr.status === 1223 ? 204 : xhr.status;
10798
10799                 // fix status code when it is 0 (0 status is undocumented).
10800                 // Occurs when accessing file resources or on Android 4.1 stock browser
10801                 // while retrieving files from application cache.
10802                 if (status === 0) {
10803                   status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
10804                 }
10805
10806                 completeRequest(callback,
10807                     status,
10808                     response,
10809                     xhr.getAllResponseHeaders(),
10810                     statusText);
10811               };
10812
10813               var requestError = function() {
10814                 // The response is always empty
10815                 // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
10816                 completeRequest(callback, -1, null, null, '');
10817               };
10818
10819               xhr.onerror = requestError;
10820               xhr.onabort = requestError;
10821
10822               if (withCredentials) {
10823                 xhr.withCredentials = true;
10824               }
10825
10826               if (responseType) {
10827                 try {
10828                   xhr.responseType = responseType;
10829                 } catch (e) {
10830                   // WebKit added support for the json responseType value on 09/03/2013
10831                   // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
10832                   // known to throw when setting the value "json" as the response type. Other older
10833                   // browsers implementing the responseType
10834                   //
10835                   // The json response type can be ignored if not supported, because JSON payloads are
10836                   // parsed on the client-side regardless.
10837                   if (responseType !== 'json') {
10838                     throw e;
10839                   }
10840                 }
10841               }
10842
10843               xhr.send(isUndefined(post) ? null : post);
10844             }
10845
10846             if (timeout > 0) {
10847               var timeoutId = $browserDefer(timeoutRequest, timeout);
10848             } else if (isPromiseLike(timeout)) {
10849               timeout.then(timeoutRequest);
10850             }
10851
10852
10853             function timeoutRequest() {
10854               jsonpDone && jsonpDone();
10855               xhr && xhr.abort();
10856             }
10857
10858             function completeRequest(callback, status, response, headersString, statusText) {
10859               // cancel timeout and subsequent timeout promise resolution
10860               if (isDefined(timeoutId)) {
10861                 $browserDefer.cancel(timeoutId);
10862               }
10863               jsonpDone = xhr = null;
10864
10865               callback(status, response, headersString, statusText);
10866               $browser.$$completeOutstandingRequest(noop);
10867             }
10868           };
10869
10870           function jsonpReq(url, callbackId, done) {
10871             // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
10872             // - fetches local scripts via XHR and evals them
10873             // - adds and immediately removes script elements from the document
10874             var script = rawDocument.createElement('script'), callback = null;
10875             script.type = "text/javascript";
10876             script.src = url;
10877             script.async = true;
10878
10879             callback = function(event) {
10880               removeEventListenerFn(script, "load", callback);
10881               removeEventListenerFn(script, "error", callback);
10882               rawDocument.body.removeChild(script);
10883               script = null;
10884               var status = -1;
10885               var text = "unknown";
10886
10887               if (event) {
10888                 if (event.type === "load" && !callbacks[callbackId].called) {
10889                   event = { type: "error" };
10890                 }
10891                 text = event.type;
10892                 status = event.type === "error" ? 404 : 200;
10893               }
10894
10895               if (done) {
10896                 done(status, text);
10897               }
10898             };
10899
10900             addEventListenerFn(script, "load", callback);
10901             addEventListenerFn(script, "error", callback);
10902             rawDocument.body.appendChild(script);
10903             return callback;
10904           }
10905         }
10906
10907         var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
10908         $interpolateMinErr.throwNoconcat = function(text) {
10909           throw $interpolateMinErr('noconcat',
10910               "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
10911               "interpolations that concatenate multiple expressions when a trusted value is " +
10912               "required.  See http://docs.angularjs.org/api/ng.$sce", text);
10913         };
10914
10915         $interpolateMinErr.interr = function(text, err) {
10916           return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
10917         };
10918
10919         /**
10920          * @ngdoc provider
10921          * @name $interpolateProvider
10922          *
10923          * @description
10924          *
10925          * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
10926          *
10927          * @example
10928         <example module="customInterpolationApp">
10929         <file name="index.html">
10930         <script>
10931           var customInterpolationApp = angular.module('customInterpolationApp', []);
10932
10933           customInterpolationApp.config(function($interpolateProvider) {
10934             $interpolateProvider.startSymbol('//');
10935             $interpolateProvider.endSymbol('//');
10936           });
10937
10938
10939           customInterpolationApp.controller('DemoController', function() {
10940               this.label = "This binding is brought you by // interpolation symbols.";
10941           });
10942         </script>
10943         <div ng-app="App" ng-controller="DemoController as demo">
10944             //demo.label//
10945         </div>
10946         </file>
10947         <file name="protractor.js" type="protractor">
10948           it('should interpolate binding with custom symbols', function() {
10949             expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
10950           });
10951         </file>
10952         </example>
10953          */
10954         function $InterpolateProvider() {
10955           var startSymbol = '{{';
10956           var endSymbol = '}}';
10957
10958           /**
10959            * @ngdoc method
10960            * @name $interpolateProvider#startSymbol
10961            * @description
10962            * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
10963            *
10964            * @param {string=} value new value to set the starting symbol to.
10965            * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10966            */
10967           this.startSymbol = function(value) {
10968             if (value) {
10969               startSymbol = value;
10970               return this;
10971             } else {
10972               return startSymbol;
10973             }
10974           };
10975
10976           /**
10977            * @ngdoc method
10978            * @name $interpolateProvider#endSymbol
10979            * @description
10980            * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10981            *
10982            * @param {string=} value new value to set the ending symbol to.
10983            * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10984            */
10985           this.endSymbol = function(value) {
10986             if (value) {
10987               endSymbol = value;
10988               return this;
10989             } else {
10990               return endSymbol;
10991             }
10992           };
10993
10994
10995           this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
10996             var startSymbolLength = startSymbol.length,
10997                 endSymbolLength = endSymbol.length,
10998                 escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
10999                 escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
11000
11001             function escape(ch) {
11002               return '\\\\\\' + ch;
11003             }
11004
11005             function unescapeText(text) {
11006               return text.replace(escapedStartRegexp, startSymbol).
11007                 replace(escapedEndRegexp, endSymbol);
11008             }
11009
11010             function stringify(value) {
11011               if (value == null) { // null || undefined
11012                 return '';
11013               }
11014               switch (typeof value) {
11015                 case 'string':
11016                   break;
11017                 case 'number':
11018                   value = '' + value;
11019                   break;
11020                 default:
11021                   value = toJson(value);
11022               }
11023
11024               return value;
11025             }
11026
11027             /**
11028              * @ngdoc service
11029              * @name $interpolate
11030              * @kind function
11031              *
11032              * @requires $parse
11033              * @requires $sce
11034              *
11035              * @description
11036              *
11037              * Compiles a string with markup into an interpolation function. This service is used by the
11038              * HTML {@link ng.$compile $compile} service for data binding. See
11039              * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
11040              * interpolation markup.
11041              *
11042              *
11043              * ```js
11044              *   var $interpolate = ...; // injected
11045              *   var exp = $interpolate('Hello {{name | uppercase}}!');
11046              *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
11047              * ```
11048              *
11049              * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
11050              * `true`, the interpolation function will return `undefined` unless all embedded expressions
11051              * evaluate to a value other than `undefined`.
11052              *
11053              * ```js
11054              *   var $interpolate = ...; // injected
11055              *   var context = {greeting: 'Hello', name: undefined };
11056              *
11057              *   // default "forgiving" mode
11058              *   var exp = $interpolate('{{greeting}} {{name}}!');
11059              *   expect(exp(context)).toEqual('Hello !');
11060              *
11061              *   // "allOrNothing" mode
11062              *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
11063              *   expect(exp(context)).toBeUndefined();
11064              *   context.name = 'Angular';
11065              *   expect(exp(context)).toEqual('Hello Angular!');
11066              * ```
11067              *
11068              * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
11069              *
11070              * ####Escaped Interpolation
11071              * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
11072              * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
11073              * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
11074              * or binding.
11075              *
11076              * This enables web-servers to prevent script injection attacks and defacing attacks, to some
11077              * degree, while also enabling code examples to work without relying on the
11078              * {@link ng.directive:ngNonBindable ngNonBindable} directive.
11079              *
11080              * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
11081              * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
11082              * interpolation start/end markers with their escaped counterparts.**
11083              *
11084              * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
11085              * output when the $interpolate service processes the text. So, for HTML elements interpolated
11086              * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
11087              * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
11088              * this is typically useful only when user-data is used in rendering a template from the server, or
11089              * when otherwise untrusted data is used by a directive.
11090              *
11091              * <example>
11092              *  <file name="index.html">
11093              *    <div ng-init="username='A user'">
11094              *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
11095              *        </p>
11096              *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
11097              *        application, but fails to accomplish their task, because the server has correctly
11098              *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
11099              *        characters.</p>
11100              *      <p>Instead, the result of the attempted script injection is visible, and can be removed
11101              *        from the database by an administrator.</p>
11102              *    </div>
11103              *  </file>
11104              * </example>
11105              *
11106              * @param {string} text The text with markup to interpolate.
11107              * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
11108              *    embedded expression in order to return an interpolation function. Strings with no
11109              *    embedded expression will return null for the interpolation function.
11110              * @param {string=} trustedContext when provided, the returned function passes the interpolated
11111              *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
11112              *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
11113              *    provides Strict Contextual Escaping for details.
11114              * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
11115              *    unless all embedded expressions evaluate to a value other than `undefined`.
11116              * @returns {function(context)} an interpolation function which is used to compute the
11117              *    interpolated string. The function has these parameters:
11118              *
11119              * - `context`: evaluation context for all expressions embedded in the interpolated text
11120              */
11121             function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
11122               allOrNothing = !!allOrNothing;
11123               var startIndex,
11124                   endIndex,
11125                   index = 0,
11126                   expressions = [],
11127                   parseFns = [],
11128                   textLength = text.length,
11129                   exp,
11130                   concat = [],
11131                   expressionPositions = [];
11132
11133               while (index < textLength) {
11134                 if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
11135                      ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
11136                   if (index !== startIndex) {
11137                     concat.push(unescapeText(text.substring(index, startIndex)));
11138                   }
11139                   exp = text.substring(startIndex + startSymbolLength, endIndex);
11140                   expressions.push(exp);
11141                   parseFns.push($parse(exp, parseStringifyInterceptor));
11142                   index = endIndex + endSymbolLength;
11143                   expressionPositions.push(concat.length);
11144                   concat.push('');
11145                 } else {
11146                   // we did not find an interpolation, so we have to add the remainder to the separators array
11147                   if (index !== textLength) {
11148                     concat.push(unescapeText(text.substring(index)));
11149                   }
11150                   break;
11151                 }
11152               }
11153
11154               // Concatenating expressions makes it hard to reason about whether some combination of
11155               // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
11156               // single expression be used for iframe[src], object[src], etc., we ensure that the value
11157               // that's used is assigned or constructed by some JS code somewhere that is more testable or
11158               // make it obvious that you bound the value to some user controlled value.  This helps reduce
11159               // the load when auditing for XSS issues.
11160               if (trustedContext && concat.length > 1) {
11161                   $interpolateMinErr.throwNoconcat(text);
11162               }
11163
11164               if (!mustHaveExpression || expressions.length) {
11165                 var compute = function(values) {
11166                   for (var i = 0, ii = expressions.length; i < ii; i++) {
11167                     if (allOrNothing && isUndefined(values[i])) return;
11168                     concat[expressionPositions[i]] = values[i];
11169                   }
11170                   return concat.join('');
11171                 };
11172
11173                 var getValue = function(value) {
11174                   return trustedContext ?
11175                     $sce.getTrusted(trustedContext, value) :
11176                     $sce.valueOf(value);
11177                 };
11178
11179                 return extend(function interpolationFn(context) {
11180                     var i = 0;
11181                     var ii = expressions.length;
11182                     var values = new Array(ii);
11183
11184                     try {
11185                       for (; i < ii; i++) {
11186                         values[i] = parseFns[i](context);
11187                       }
11188
11189                       return compute(values);
11190                     } catch (err) {
11191                       $exceptionHandler($interpolateMinErr.interr(text, err));
11192                     }
11193
11194                   }, {
11195                   // all of these properties are undocumented for now
11196                   exp: text, //just for compatibility with regular watchers created via $watch
11197                   expressions: expressions,
11198                   $$watchDelegate: function(scope, listener) {
11199                     var lastValue;
11200                     return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
11201                       var currValue = compute(values);
11202                       if (isFunction(listener)) {
11203                         listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
11204                       }
11205                       lastValue = currValue;
11206                     });
11207                   }
11208                 });
11209               }
11210
11211               function parseStringifyInterceptor(value) {
11212                 try {
11213                   value = getValue(value);
11214                   return allOrNothing && !isDefined(value) ? value : stringify(value);
11215                 } catch (err) {
11216                   $exceptionHandler($interpolateMinErr.interr(text, err));
11217                 }
11218               }
11219             }
11220
11221
11222             /**
11223              * @ngdoc method
11224              * @name $interpolate#startSymbol
11225              * @description
11226              * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
11227              *
11228              * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
11229              * the symbol.
11230              *
11231              * @returns {string} start symbol.
11232              */
11233             $interpolate.startSymbol = function() {
11234               return startSymbol;
11235             };
11236
11237
11238             /**
11239              * @ngdoc method
11240              * @name $interpolate#endSymbol
11241              * @description
11242              * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
11243              *
11244              * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
11245              * the symbol.
11246              *
11247              * @returns {string} end symbol.
11248              */
11249             $interpolate.endSymbol = function() {
11250               return endSymbol;
11251             };
11252
11253             return $interpolate;
11254           }];
11255         }
11256
11257         function $IntervalProvider() {
11258           this.$get = ['$rootScope', '$window', '$q', '$$q',
11259                function($rootScope,   $window,   $q,   $$q) {
11260             var intervals = {};
11261
11262
11263              /**
11264               * @ngdoc service
11265               * @name $interval
11266               *
11267               * @description
11268               * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
11269               * milliseconds.
11270               *
11271               * The return value of registering an interval function is a promise. This promise will be
11272               * notified upon each tick of the interval, and will be resolved after `count` iterations, or
11273               * run indefinitely if `count` is not defined. The value of the notification will be the
11274               * number of iterations that have run.
11275               * To cancel an interval, call `$interval.cancel(promise)`.
11276               *
11277               * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
11278               * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
11279               * time.
11280               *
11281               * <div class="alert alert-warning">
11282               * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
11283               * with them.  In particular they are not automatically destroyed when a controller's scope or a
11284               * directive's element are destroyed.
11285               * You should take this into consideration and make sure to always cancel the interval at the
11286               * appropriate moment.  See the example below for more details on how and when to do this.
11287               * </div>
11288               *
11289               * @param {function()} fn A function that should be called repeatedly.
11290               * @param {number} delay Number of milliseconds between each function call.
11291               * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
11292               *   indefinitely.
11293               * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
11294               *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
11295               * @param {...*=} Pass additional parameters to the executed function.
11296               * @returns {promise} A promise which will be notified on each iteration.
11297               *
11298               * @example
11299               * <example module="intervalExample">
11300               * <file name="index.html">
11301               *   <script>
11302               *     angular.module('intervalExample', [])
11303               *       .controller('ExampleController', ['$scope', '$interval',
11304               *         function($scope, $interval) {
11305               *           $scope.format = 'M/d/yy h:mm:ss a';
11306               *           $scope.blood_1 = 100;
11307               *           $scope.blood_2 = 120;
11308               *
11309               *           var stop;
11310               *           $scope.fight = function() {
11311               *             // Don't start a new fight if we are already fighting
11312               *             if ( angular.isDefined(stop) ) return;
11313               *
11314               *             stop = $interval(function() {
11315               *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
11316               *                 $scope.blood_1 = $scope.blood_1 - 3;
11317               *                 $scope.blood_2 = $scope.blood_2 - 4;
11318               *               } else {
11319               *                 $scope.stopFight();
11320               *               }
11321               *             }, 100);
11322               *           };
11323               *
11324               *           $scope.stopFight = function() {
11325               *             if (angular.isDefined(stop)) {
11326               *               $interval.cancel(stop);
11327               *               stop = undefined;
11328               *             }
11329               *           };
11330               *
11331               *           $scope.resetFight = function() {
11332               *             $scope.blood_1 = 100;
11333               *             $scope.blood_2 = 120;
11334               *           };
11335               *
11336               *           $scope.$on('$destroy', function() {
11337               *             // Make sure that the interval is destroyed too
11338               *             $scope.stopFight();
11339               *           });
11340               *         }])
11341               *       // Register the 'myCurrentTime' directive factory method.
11342               *       // We inject $interval and dateFilter service since the factory method is DI.
11343               *       .directive('myCurrentTime', ['$interval', 'dateFilter',
11344               *         function($interval, dateFilter) {
11345               *           // return the directive link function. (compile function not needed)
11346               *           return function(scope, element, attrs) {
11347               *             var format,  // date format
11348               *                 stopTime; // so that we can cancel the time updates
11349               *
11350               *             // used to update the UI
11351               *             function updateTime() {
11352               *               element.text(dateFilter(new Date(), format));
11353               *             }
11354               *
11355               *             // watch the expression, and update the UI on change.
11356               *             scope.$watch(attrs.myCurrentTime, function(value) {
11357               *               format = value;
11358               *               updateTime();
11359               *             });
11360               *
11361               *             stopTime = $interval(updateTime, 1000);
11362               *
11363               *             // listen on DOM destroy (removal) event, and cancel the next UI update
11364               *             // to prevent updating time after the DOM element was removed.
11365               *             element.on('$destroy', function() {
11366               *               $interval.cancel(stopTime);
11367               *             });
11368               *           }
11369               *         }]);
11370               *   </script>
11371               *
11372               *   <div>
11373               *     <div ng-controller="ExampleController">
11374               *       <label>Date format: <input ng-model="format"></label> <hr/>
11375               *       Current time is: <span my-current-time="format"></span>
11376               *       <hr/>
11377               *       Blood 1 : <font color='red'>{{blood_1}}</font>
11378               *       Blood 2 : <font color='red'>{{blood_2}}</font>
11379               *       <button type="button" data-ng-click="fight()">Fight</button>
11380               *       <button type="button" data-ng-click="stopFight()">StopFight</button>
11381               *       <button type="button" data-ng-click="resetFight()">resetFight</button>
11382               *     </div>
11383               *   </div>
11384               *
11385               * </file>
11386               * </example>
11387               */
11388             function interval(fn, delay, count, invokeApply) {
11389               var hasParams = arguments.length > 4,
11390                   args = hasParams ? sliceArgs(arguments, 4) : [],
11391                   setInterval = $window.setInterval,
11392                   clearInterval = $window.clearInterval,
11393                   iteration = 0,
11394                   skipApply = (isDefined(invokeApply) && !invokeApply),
11395                   deferred = (skipApply ? $$q : $q).defer(),
11396                   promise = deferred.promise;
11397
11398               count = isDefined(count) ? count : 0;
11399
11400               promise.then(null, null, (!hasParams) ? fn : function() {
11401                 fn.apply(null, args);
11402               });
11403
11404               promise.$$intervalId = setInterval(function tick() {
11405                 deferred.notify(iteration++);
11406
11407                 if (count > 0 && iteration >= count) {
11408                   deferred.resolve(iteration);
11409                   clearInterval(promise.$$intervalId);
11410                   delete intervals[promise.$$intervalId];
11411                 }
11412
11413                 if (!skipApply) $rootScope.$apply();
11414
11415               }, delay);
11416
11417               intervals[promise.$$intervalId] = deferred;
11418
11419               return promise;
11420             }
11421
11422
11423              /**
11424               * @ngdoc method
11425               * @name $interval#cancel
11426               *
11427               * @description
11428               * Cancels a task associated with the `promise`.
11429               *
11430               * @param {Promise=} promise returned by the `$interval` function.
11431               * @returns {boolean} Returns `true` if the task was successfully canceled.
11432               */
11433             interval.cancel = function(promise) {
11434               if (promise && promise.$$intervalId in intervals) {
11435                 intervals[promise.$$intervalId].reject('canceled');
11436                 $window.clearInterval(promise.$$intervalId);
11437                 delete intervals[promise.$$intervalId];
11438                 return true;
11439               }
11440               return false;
11441             };
11442
11443             return interval;
11444           }];
11445         }
11446
11447         /**
11448          * @ngdoc service
11449          * @name $locale
11450          *
11451          * @description
11452          * $locale service provides localization rules for various Angular components. As of right now the
11453          * only public api is:
11454          *
11455          * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
11456          */
11457
11458         var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
11459             DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
11460         var $locationMinErr = minErr('$location');
11461
11462
11463         /**
11464          * Encode path using encodeUriSegment, ignoring forward slashes
11465          *
11466          * @param {string} path Path to encode
11467          * @returns {string}
11468          */
11469         function encodePath(path) {
11470           var segments = path.split('/'),
11471               i = segments.length;
11472
11473           while (i--) {
11474             segments[i] = encodeUriSegment(segments[i]);
11475           }
11476
11477           return segments.join('/');
11478         }
11479
11480         function parseAbsoluteUrl(absoluteUrl, locationObj) {
11481           var parsedUrl = urlResolve(absoluteUrl);
11482
11483           locationObj.$$protocol = parsedUrl.protocol;
11484           locationObj.$$host = parsedUrl.hostname;
11485           locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
11486         }
11487
11488
11489         function parseAppUrl(relativeUrl, locationObj) {
11490           var prefixed = (relativeUrl.charAt(0) !== '/');
11491           if (prefixed) {
11492             relativeUrl = '/' + relativeUrl;
11493           }
11494           var match = urlResolve(relativeUrl);
11495           locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
11496               match.pathname.substring(1) : match.pathname);
11497           locationObj.$$search = parseKeyValue(match.search);
11498           locationObj.$$hash = decodeURIComponent(match.hash);
11499
11500           // make sure path starts with '/';
11501           if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
11502             locationObj.$$path = '/' + locationObj.$$path;
11503           }
11504         }
11505
11506
11507         /**
11508          *
11509          * @param {string} begin
11510          * @param {string} whole
11511          * @returns {string} returns text from whole after begin or undefined if it does not begin with
11512          *                   expected string.
11513          */
11514         function beginsWith(begin, whole) {
11515           if (whole.indexOf(begin) === 0) {
11516             return whole.substr(begin.length);
11517           }
11518         }
11519
11520
11521         function stripHash(url) {
11522           var index = url.indexOf('#');
11523           return index == -1 ? url : url.substr(0, index);
11524         }
11525
11526         function trimEmptyHash(url) {
11527           return url.replace(/(#.+)|#$/, '$1');
11528         }
11529
11530
11531         function stripFile(url) {
11532           return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
11533         }
11534
11535         /* return the server only (scheme://host:port) */
11536         function serverBase(url) {
11537           return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
11538         }
11539
11540
11541         /**
11542          * LocationHtml5Url represents an url
11543          * This object is exposed as $location service when HTML5 mode is enabled and supported
11544          *
11545          * @constructor
11546          * @param {string} appBase application base URL
11547          * @param {string} appBaseNoFile application base URL stripped of any filename
11548          * @param {string} basePrefix url path prefix
11549          */
11550         function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
11551           this.$$html5 = true;
11552           basePrefix = basePrefix || '';
11553           parseAbsoluteUrl(appBase, this);
11554
11555
11556           /**
11557            * Parse given html5 (regular) url string into properties
11558            * @param {string} url HTML5 url
11559            * @private
11560            */
11561           this.$$parse = function(url) {
11562             var pathUrl = beginsWith(appBaseNoFile, url);
11563             if (!isString(pathUrl)) {
11564               throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
11565                   appBaseNoFile);
11566             }
11567
11568             parseAppUrl(pathUrl, this);
11569
11570             if (!this.$$path) {
11571               this.$$path = '/';
11572             }
11573
11574             this.$$compose();
11575           };
11576
11577           /**
11578            * Compose url and update `absUrl` property
11579            * @private
11580            */
11581           this.$$compose = function() {
11582             var search = toKeyValue(this.$$search),
11583                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11584
11585             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11586             this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
11587           };
11588
11589           this.$$parseLinkUrl = function(url, relHref) {
11590             if (relHref && relHref[0] === '#') {
11591               // special case for links to hash fragments:
11592               // keep the old url and only replace the hash fragment
11593               this.hash(relHref.slice(1));
11594               return true;
11595             }
11596             var appUrl, prevAppUrl;
11597             var rewrittenUrl;
11598
11599             if (isDefined(appUrl = beginsWith(appBase, url))) {
11600               prevAppUrl = appUrl;
11601               if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
11602                 rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
11603               } else {
11604                 rewrittenUrl = appBase + prevAppUrl;
11605               }
11606             } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
11607               rewrittenUrl = appBaseNoFile + appUrl;
11608             } else if (appBaseNoFile == url + '/') {
11609               rewrittenUrl = appBaseNoFile;
11610             }
11611             if (rewrittenUrl) {
11612               this.$$parse(rewrittenUrl);
11613             }
11614             return !!rewrittenUrl;
11615           };
11616         }
11617
11618
11619         /**
11620          * LocationHashbangUrl represents url
11621          * This object is exposed as $location service when developer doesn't opt into html5 mode.
11622          * It also serves as the base class for html5 mode fallback on legacy browsers.
11623          *
11624          * @constructor
11625          * @param {string} appBase application base URL
11626          * @param {string} appBaseNoFile application base URL stripped of any filename
11627          * @param {string} hashPrefix hashbang prefix
11628          */
11629         function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
11630
11631           parseAbsoluteUrl(appBase, this);
11632
11633
11634           /**
11635            * Parse given hashbang url into properties
11636            * @param {string} url Hashbang url
11637            * @private
11638            */
11639           this.$$parse = function(url) {
11640             var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
11641             var withoutHashUrl;
11642
11643             if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
11644
11645               // The rest of the url starts with a hash so we have
11646               // got either a hashbang path or a plain hash fragment
11647               withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
11648               if (isUndefined(withoutHashUrl)) {
11649                 // There was no hashbang prefix so we just have a hash fragment
11650                 withoutHashUrl = withoutBaseUrl;
11651               }
11652
11653             } else {
11654               // There was no hashbang path nor hash fragment:
11655               // If we are in HTML5 mode we use what is left as the path;
11656               // Otherwise we ignore what is left
11657               if (this.$$html5) {
11658                 withoutHashUrl = withoutBaseUrl;
11659               } else {
11660                 withoutHashUrl = '';
11661                 if (isUndefined(withoutBaseUrl)) {
11662                   appBase = url;
11663                   this.replace();
11664                 }
11665               }
11666             }
11667
11668             parseAppUrl(withoutHashUrl, this);
11669
11670             this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
11671
11672             this.$$compose();
11673
11674             /*
11675              * In Windows, on an anchor node on documents loaded from
11676              * the filesystem, the browser will return a pathname
11677              * prefixed with the drive name ('/C:/path') when a
11678              * pathname without a drive is set:
11679              *  * a.setAttribute('href', '/foo')
11680              *   * a.pathname === '/C:/foo' //true
11681              *
11682              * Inside of Angular, we're always using pathnames that
11683              * do not include drive names for routing.
11684              */
11685             function removeWindowsDriveName(path, url, base) {
11686               /*
11687               Matches paths for file protocol on windows,
11688               such as /C:/foo/bar, and captures only /foo/bar.
11689               */
11690               var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
11691
11692               var firstPathSegmentMatch;
11693
11694               //Get the relative path from the input URL.
11695               if (url.indexOf(base) === 0) {
11696                 url = url.replace(base, '');
11697               }
11698
11699               // The input URL intentionally contains a first path segment that ends with a colon.
11700               if (windowsFilePathExp.exec(url)) {
11701                 return path;
11702               }
11703
11704               firstPathSegmentMatch = windowsFilePathExp.exec(path);
11705               return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
11706             }
11707           };
11708
11709           /**
11710            * Compose hashbang url and update `absUrl` property
11711            * @private
11712            */
11713           this.$$compose = function() {
11714             var search = toKeyValue(this.$$search),
11715                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11716
11717             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11718             this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
11719           };
11720
11721           this.$$parseLinkUrl = function(url, relHref) {
11722             if (stripHash(appBase) == stripHash(url)) {
11723               this.$$parse(url);
11724               return true;
11725             }
11726             return false;
11727           };
11728         }
11729
11730
11731         /**
11732          * LocationHashbangUrl represents url
11733          * This object is exposed as $location service when html5 history api is enabled but the browser
11734          * does not support it.
11735          *
11736          * @constructor
11737          * @param {string} appBase application base URL
11738          * @param {string} appBaseNoFile application base URL stripped of any filename
11739          * @param {string} hashPrefix hashbang prefix
11740          */
11741         function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
11742           this.$$html5 = true;
11743           LocationHashbangUrl.apply(this, arguments);
11744
11745           this.$$parseLinkUrl = function(url, relHref) {
11746             if (relHref && relHref[0] === '#') {
11747               // special case for links to hash fragments:
11748               // keep the old url and only replace the hash fragment
11749               this.hash(relHref.slice(1));
11750               return true;
11751             }
11752
11753             var rewrittenUrl;
11754             var appUrl;
11755
11756             if (appBase == stripHash(url)) {
11757               rewrittenUrl = url;
11758             } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
11759               rewrittenUrl = appBase + hashPrefix + appUrl;
11760             } else if (appBaseNoFile === url + '/') {
11761               rewrittenUrl = appBaseNoFile;
11762             }
11763             if (rewrittenUrl) {
11764               this.$$parse(rewrittenUrl);
11765             }
11766             return !!rewrittenUrl;
11767           };
11768
11769           this.$$compose = function() {
11770             var search = toKeyValue(this.$$search),
11771                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11772
11773             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11774             // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
11775             this.$$absUrl = appBase + hashPrefix + this.$$url;
11776           };
11777
11778         }
11779
11780
11781         var locationPrototype = {
11782
11783           /**
11784            * Are we in html5 mode?
11785            * @private
11786            */
11787           $$html5: false,
11788
11789           /**
11790            * Has any change been replacing?
11791            * @private
11792            */
11793           $$replace: false,
11794
11795           /**
11796            * @ngdoc method
11797            * @name $location#absUrl
11798            *
11799            * @description
11800            * This method is getter only.
11801            *
11802            * Return full url representation with all segments encoded according to rules specified in
11803            * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
11804            *
11805            *
11806            * ```js
11807            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11808            * var absUrl = $location.absUrl();
11809            * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
11810            * ```
11811            *
11812            * @return {string} full url
11813            */
11814           absUrl: locationGetter('$$absUrl'),
11815
11816           /**
11817            * @ngdoc method
11818            * @name $location#url
11819            *
11820            * @description
11821            * This method is getter / setter.
11822            *
11823            * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
11824            *
11825            * Change path, search and hash, when called with parameter and return `$location`.
11826            *
11827            *
11828            * ```js
11829            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11830            * var url = $location.url();
11831            * // => "/some/path?foo=bar&baz=xoxo"
11832            * ```
11833            *
11834            * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
11835            * @return {string} url
11836            */
11837           url: function(url) {
11838             if (isUndefined(url)) {
11839               return this.$$url;
11840             }
11841
11842             var match = PATH_MATCH.exec(url);
11843             if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
11844             if (match[2] || match[1] || url === '') this.search(match[3] || '');
11845             this.hash(match[5] || '');
11846
11847             return this;
11848           },
11849
11850           /**
11851            * @ngdoc method
11852            * @name $location#protocol
11853            *
11854            * @description
11855            * This method is getter only.
11856            *
11857            * Return protocol of current url.
11858            *
11859            *
11860            * ```js
11861            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11862            * var protocol = $location.protocol();
11863            * // => "http"
11864            * ```
11865            *
11866            * @return {string} protocol of current url
11867            */
11868           protocol: locationGetter('$$protocol'),
11869
11870           /**
11871            * @ngdoc method
11872            * @name $location#host
11873            *
11874            * @description
11875            * This method is getter only.
11876            *
11877            * Return host of current url.
11878            *
11879            * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
11880            *
11881            *
11882            * ```js
11883            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11884            * var host = $location.host();
11885            * // => "example.com"
11886            *
11887            * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
11888            * host = $location.host();
11889            * // => "example.com"
11890            * host = location.host;
11891            * // => "example.com:8080"
11892            * ```
11893            *
11894            * @return {string} host of current url.
11895            */
11896           host: locationGetter('$$host'),
11897
11898           /**
11899            * @ngdoc method
11900            * @name $location#port
11901            *
11902            * @description
11903            * This method is getter only.
11904            *
11905            * Return port of current url.
11906            *
11907            *
11908            * ```js
11909            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11910            * var port = $location.port();
11911            * // => 80
11912            * ```
11913            *
11914            * @return {Number} port
11915            */
11916           port: locationGetter('$$port'),
11917
11918           /**
11919            * @ngdoc method
11920            * @name $location#path
11921            *
11922            * @description
11923            * This method is getter / setter.
11924            *
11925            * Return path of current url when called without any parameter.
11926            *
11927            * Change path when called with parameter and return `$location`.
11928            *
11929            * Note: Path should always begin with forward slash (/), this method will add the forward slash
11930            * if it is missing.
11931            *
11932            *
11933            * ```js
11934            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11935            * var path = $location.path();
11936            * // => "/some/path"
11937            * ```
11938            *
11939            * @param {(string|number)=} path New path
11940            * @return {string} path
11941            */
11942           path: locationGetterSetter('$$path', function(path) {
11943             path = path !== null ? path.toString() : '';
11944             return path.charAt(0) == '/' ? path : '/' + path;
11945           }),
11946
11947           /**
11948            * @ngdoc method
11949            * @name $location#search
11950            *
11951            * @description
11952            * This method is getter / setter.
11953            *
11954            * Return search part (as object) of current url when called without any parameter.
11955            *
11956            * Change search part when called with parameter and return `$location`.
11957            *
11958            *
11959            * ```js
11960            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11961            * var searchObject = $location.search();
11962            * // => {foo: 'bar', baz: 'xoxo'}
11963            *
11964            * // set foo to 'yipee'
11965            * $location.search('foo', 'yipee');
11966            * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
11967            * ```
11968            *
11969            * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
11970            * hash object.
11971            *
11972            * When called with a single argument the method acts as a setter, setting the `search` component
11973            * of `$location` to the specified value.
11974            *
11975            * If the argument is a hash object containing an array of values, these values will be encoded
11976            * as duplicate search parameters in the url.
11977            *
11978            * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
11979            * will override only a single search property.
11980            *
11981            * If `paramValue` is an array, it will override the property of the `search` component of
11982            * `$location` specified via the first argument.
11983            *
11984            * If `paramValue` is `null`, the property specified via the first argument will be deleted.
11985            *
11986            * If `paramValue` is `true`, the property specified via the first argument will be added with no
11987            * value nor trailing equal sign.
11988            *
11989            * @return {Object} If called with no arguments returns the parsed `search` object. If called with
11990            * one or more arguments returns `$location` object itself.
11991            */
11992           search: function(search, paramValue) {
11993             switch (arguments.length) {
11994               case 0:
11995                 return this.$$search;
11996               case 1:
11997                 if (isString(search) || isNumber(search)) {
11998                   search = search.toString();
11999                   this.$$search = parseKeyValue(search);
12000                 } else if (isObject(search)) {
12001                   search = copy(search, {});
12002                   // remove object undefined or null properties
12003                   forEach(search, function(value, key) {
12004                     if (value == null) delete search[key];
12005                   });
12006
12007                   this.$$search = search;
12008                 } else {
12009                   throw $locationMinErr('isrcharg',
12010                       'The first argument of the `$location#search()` call must be a string or an object.');
12011                 }
12012                 break;
12013               default:
12014                 if (isUndefined(paramValue) || paramValue === null) {
12015                   delete this.$$search[search];
12016                 } else {
12017                   this.$$search[search] = paramValue;
12018                 }
12019             }
12020
12021             this.$$compose();
12022             return this;
12023           },
12024
12025           /**
12026            * @ngdoc method
12027            * @name $location#hash
12028            *
12029            * @description
12030            * This method is getter / setter.
12031            *
12032            * Returns the hash fragment when called without any parameters.
12033            *
12034            * Changes the hash fragment when called with a parameter and returns `$location`.
12035            *
12036            *
12037            * ```js
12038            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
12039            * var hash = $location.hash();
12040            * // => "hashValue"
12041            * ```
12042            *
12043            * @param {(string|number)=} hash New hash fragment
12044            * @return {string} hash
12045            */
12046           hash: locationGetterSetter('$$hash', function(hash) {
12047             return hash !== null ? hash.toString() : '';
12048           }),
12049
12050           /**
12051            * @ngdoc method
12052            * @name $location#replace
12053            *
12054            * @description
12055            * If called, all changes to $location during the current `$digest` will replace the current history
12056            * record, instead of adding a new one.
12057            */
12058           replace: function() {
12059             this.$$replace = true;
12060             return this;
12061           }
12062         };
12063
12064         forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
12065           Location.prototype = Object.create(locationPrototype);
12066
12067           /**
12068            * @ngdoc method
12069            * @name $location#state
12070            *
12071            * @description
12072            * This method is getter / setter.
12073            *
12074            * Return the history state object when called without any parameter.
12075            *
12076            * Change the history state object when called with one parameter and return `$location`.
12077            * The state object is later passed to `pushState` or `replaceState`.
12078            *
12079            * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
12080            * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
12081            * older browsers (like IE9 or Android < 4.0), don't use this method.
12082            *
12083            * @param {object=} state State object for pushState or replaceState
12084            * @return {object} state
12085            */
12086           Location.prototype.state = function(state) {
12087             if (!arguments.length) {
12088               return this.$$state;
12089             }
12090
12091             if (Location !== LocationHtml5Url || !this.$$html5) {
12092               throw $locationMinErr('nostate', 'History API state support is available only ' +
12093                 'in HTML5 mode and only in browsers supporting HTML5 History API');
12094             }
12095             // The user might modify `stateObject` after invoking `$location.state(stateObject)`
12096             // but we're changing the $$state reference to $browser.state() during the $digest
12097             // so the modification window is narrow.
12098             this.$$state = isUndefined(state) ? null : state;
12099
12100             return this;
12101           };
12102         });
12103
12104
12105         function locationGetter(property) {
12106           return function() {
12107             return this[property];
12108           };
12109         }
12110
12111
12112         function locationGetterSetter(property, preprocess) {
12113           return function(value) {
12114             if (isUndefined(value)) {
12115               return this[property];
12116             }
12117
12118             this[property] = preprocess(value);
12119             this.$$compose();
12120
12121             return this;
12122           };
12123         }
12124
12125
12126         /**
12127          * @ngdoc service
12128          * @name $location
12129          *
12130          * @requires $rootElement
12131          *
12132          * @description
12133          * The $location service parses the URL in the browser address bar (based on the
12134          * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
12135          * available to your application. Changes to the URL in the address bar are reflected into
12136          * $location service and changes to $location are reflected into the browser address bar.
12137          *
12138          * **The $location service:**
12139          *
12140          * - Exposes the current URL in the browser address bar, so you can
12141          *   - Watch and observe the URL.
12142          *   - Change the URL.
12143          * - Synchronizes the URL with the browser when the user
12144          *   - Changes the address bar.
12145          *   - Clicks the back or forward button (or clicks a History link).
12146          *   - Clicks on a link.
12147          * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
12148          *
12149          * For more information see {@link guide/$location Developer Guide: Using $location}
12150          */
12151
12152         /**
12153          * @ngdoc provider
12154          * @name $locationProvider
12155          * @description
12156          * Use the `$locationProvider` to configure how the application deep linking paths are stored.
12157          */
12158         function $LocationProvider() {
12159           var hashPrefix = '',
12160               html5Mode = {
12161                 enabled: false,
12162                 requireBase: true,
12163                 rewriteLinks: true
12164               };
12165
12166           /**
12167            * @ngdoc method
12168            * @name $locationProvider#hashPrefix
12169            * @description
12170            * @param {string=} prefix Prefix for hash part (containing path and search)
12171            * @returns {*} current value if used as getter or itself (chaining) if used as setter
12172            */
12173           this.hashPrefix = function(prefix) {
12174             if (isDefined(prefix)) {
12175               hashPrefix = prefix;
12176               return this;
12177             } else {
12178               return hashPrefix;
12179             }
12180           };
12181
12182           /**
12183            * @ngdoc method
12184            * @name $locationProvider#html5Mode
12185            * @description
12186            * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
12187            *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
12188            *   properties:
12189            *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
12190            *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
12191            *     support `pushState`.
12192            *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
12193            *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
12194            *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
12195            *     See the {@link guide/$location $location guide for more information}
12196            *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
12197            *     enables/disables url rewriting for relative links.
12198            *
12199            * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
12200            */
12201           this.html5Mode = function(mode) {
12202             if (isBoolean(mode)) {
12203               html5Mode.enabled = mode;
12204               return this;
12205             } else if (isObject(mode)) {
12206
12207               if (isBoolean(mode.enabled)) {
12208                 html5Mode.enabled = mode.enabled;
12209               }
12210
12211               if (isBoolean(mode.requireBase)) {
12212                 html5Mode.requireBase = mode.requireBase;
12213               }
12214
12215               if (isBoolean(mode.rewriteLinks)) {
12216                 html5Mode.rewriteLinks = mode.rewriteLinks;
12217               }
12218
12219               return this;
12220             } else {
12221               return html5Mode;
12222             }
12223           };
12224
12225           /**
12226            * @ngdoc event
12227            * @name $location#$locationChangeStart
12228            * @eventType broadcast on root scope
12229            * @description
12230            * Broadcasted before a URL will change.
12231            *
12232            * This change can be prevented by calling
12233            * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
12234            * details about event object. Upon successful change
12235            * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
12236            *
12237            * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
12238            * the browser supports the HTML5 History API.
12239            *
12240            * @param {Object} angularEvent Synthetic event object.
12241            * @param {string} newUrl New URL
12242            * @param {string=} oldUrl URL that was before it was changed.
12243            * @param {string=} newState New history state object
12244            * @param {string=} oldState History state object that was before it was changed.
12245            */
12246
12247           /**
12248            * @ngdoc event
12249            * @name $location#$locationChangeSuccess
12250            * @eventType broadcast on root scope
12251            * @description
12252            * Broadcasted after a URL was changed.
12253            *
12254            * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
12255            * the browser supports the HTML5 History API.
12256            *
12257            * @param {Object} angularEvent Synthetic event object.
12258            * @param {string} newUrl New URL
12259            * @param {string=} oldUrl URL that was before it was changed.
12260            * @param {string=} newState New history state object
12261            * @param {string=} oldState History state object that was before it was changed.
12262            */
12263
12264           this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
12265               function($rootScope, $browser, $sniffer, $rootElement, $window) {
12266             var $location,
12267                 LocationMode,
12268                 baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
12269                 initialUrl = $browser.url(),
12270                 appBase;
12271
12272             if (html5Mode.enabled) {
12273               if (!baseHref && html5Mode.requireBase) {
12274                 throw $locationMinErr('nobase',
12275                   "$location in HTML5 mode requires a <base> tag to be present!");
12276               }
12277               appBase = serverBase(initialUrl) + (baseHref || '/');
12278               LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
12279             } else {
12280               appBase = stripHash(initialUrl);
12281               LocationMode = LocationHashbangUrl;
12282             }
12283             var appBaseNoFile = stripFile(appBase);
12284
12285             $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
12286             $location.$$parseLinkUrl(initialUrl, initialUrl);
12287
12288             $location.$$state = $browser.state();
12289
12290             var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
12291
12292             function setBrowserUrlWithFallback(url, replace, state) {
12293               var oldUrl = $location.url();
12294               var oldState = $location.$$state;
12295               try {
12296                 $browser.url(url, replace, state);
12297
12298                 // Make sure $location.state() returns referentially identical (not just deeply equal)
12299                 // state object; this makes possible quick checking if the state changed in the digest
12300                 // loop. Checking deep equality would be too expensive.
12301                 $location.$$state = $browser.state();
12302               } catch (e) {
12303                 // Restore old values if pushState fails
12304                 $location.url(oldUrl);
12305                 $location.$$state = oldState;
12306
12307                 throw e;
12308               }
12309             }
12310
12311             $rootElement.on('click', function(event) {
12312               // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
12313               // currently we open nice url link and redirect then
12314
12315               if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
12316
12317               var elm = jqLite(event.target);
12318
12319               // traverse the DOM up to find first A tag
12320               while (nodeName_(elm[0]) !== 'a') {
12321                 // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
12322                 if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
12323               }
12324
12325               var absHref = elm.prop('href');
12326               // get the actual href attribute - see
12327               // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
12328               var relHref = elm.attr('href') || elm.attr('xlink:href');
12329
12330               if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
12331                 // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
12332                 // an animation.
12333                 absHref = urlResolve(absHref.animVal).href;
12334               }
12335
12336               // Ignore when url is started with javascript: or mailto:
12337               if (IGNORE_URI_REGEXP.test(absHref)) return;
12338
12339               if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
12340                 if ($location.$$parseLinkUrl(absHref, relHref)) {
12341                   // We do a preventDefault for all urls that are part of the angular application,
12342                   // in html5mode and also without, so that we are able to abort navigation without
12343                   // getting double entries in the location history.
12344                   event.preventDefault();
12345                   // update location manually
12346                   if ($location.absUrl() != $browser.url()) {
12347                     $rootScope.$apply();
12348                     // hack to work around FF6 bug 684208 when scenario runner clicks on links
12349                     $window.angular['ff-684208-preventDefault'] = true;
12350                   }
12351                 }
12352               }
12353             });
12354
12355
12356             // rewrite hashbang url <> html5 url
12357             if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
12358               $browser.url($location.absUrl(), true);
12359             }
12360
12361             var initializing = true;
12362
12363             // update $location when $browser url changes
12364             $browser.onUrlChange(function(newUrl, newState) {
12365
12366               if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
12367                 // If we are navigating outside of the app then force a reload
12368                 $window.location.href = newUrl;
12369                 return;
12370               }
12371
12372               $rootScope.$evalAsync(function() {
12373                 var oldUrl = $location.absUrl();
12374                 var oldState = $location.$$state;
12375                 var defaultPrevented;
12376                 newUrl = trimEmptyHash(newUrl);
12377                 $location.$$parse(newUrl);
12378                 $location.$$state = newState;
12379
12380                 defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12381                     newState, oldState).defaultPrevented;
12382
12383                 // if the location was changed by a `$locationChangeStart` handler then stop
12384                 // processing this location change
12385                 if ($location.absUrl() !== newUrl) return;
12386
12387                 if (defaultPrevented) {
12388                   $location.$$parse(oldUrl);
12389                   $location.$$state = oldState;
12390                   setBrowserUrlWithFallback(oldUrl, false, oldState);
12391                 } else {
12392                   initializing = false;
12393                   afterLocationChange(oldUrl, oldState);
12394                 }
12395               });
12396               if (!$rootScope.$$phase) $rootScope.$digest();
12397             });
12398
12399             // update browser
12400             $rootScope.$watch(function $locationWatch() {
12401               var oldUrl = trimEmptyHash($browser.url());
12402               var newUrl = trimEmptyHash($location.absUrl());
12403               var oldState = $browser.state();
12404               var currentReplace = $location.$$replace;
12405               var urlOrStateChanged = oldUrl !== newUrl ||
12406                 ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
12407
12408               if (initializing || urlOrStateChanged) {
12409                 initializing = false;
12410
12411                 $rootScope.$evalAsync(function() {
12412                   var newUrl = $location.absUrl();
12413                   var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12414                       $location.$$state, oldState).defaultPrevented;
12415
12416                   // if the location was changed by a `$locationChangeStart` handler then stop
12417                   // processing this location change
12418                   if ($location.absUrl() !== newUrl) return;
12419
12420                   if (defaultPrevented) {
12421                     $location.$$parse(oldUrl);
12422                     $location.$$state = oldState;
12423                   } else {
12424                     if (urlOrStateChanged) {
12425                       setBrowserUrlWithFallback(newUrl, currentReplace,
12426                                                 oldState === $location.$$state ? null : $location.$$state);
12427                     }
12428                     afterLocationChange(oldUrl, oldState);
12429                   }
12430                 });
12431               }
12432
12433               $location.$$replace = false;
12434
12435               // we don't need to return anything because $evalAsync will make the digest loop dirty when
12436               // there is a change
12437             });
12438
12439             return $location;
12440
12441             function afterLocationChange(oldUrl, oldState) {
12442               $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
12443                 $location.$$state, oldState);
12444             }
12445         }];
12446         }
12447
12448         /**
12449          * @ngdoc service
12450          * @name $log
12451          * @requires $window
12452          *
12453          * @description
12454          * Simple service for logging. Default implementation safely writes the message
12455          * into the browser's console (if present).
12456          *
12457          * The main purpose of this service is to simplify debugging and troubleshooting.
12458          *
12459          * The default is to log `debug` messages. You can use
12460          * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
12461          *
12462          * @example
12463            <example module="logExample">
12464              <file name="script.js">
12465                angular.module('logExample', [])
12466                  .controller('LogController', ['$scope', '$log', function($scope, $log) {
12467                    $scope.$log = $log;
12468                    $scope.message = 'Hello World!';
12469                  }]);
12470              </file>
12471              <file name="index.html">
12472                <div ng-controller="LogController">
12473                  <p>Reload this page with open console, enter text and hit the log button...</p>
12474                  <label>Message:
12475                  <input type="text" ng-model="message" /></label>
12476                  <button ng-click="$log.log(message)">log</button>
12477                  <button ng-click="$log.warn(message)">warn</button>
12478                  <button ng-click="$log.info(message)">info</button>
12479                  <button ng-click="$log.error(message)">error</button>
12480                  <button ng-click="$log.debug(message)">debug</button>
12481                </div>
12482              </file>
12483            </example>
12484          */
12485
12486         /**
12487          * @ngdoc provider
12488          * @name $logProvider
12489          * @description
12490          * Use the `$logProvider` to configure how the application logs messages
12491          */
12492         function $LogProvider() {
12493           var debug = true,
12494               self = this;
12495
12496           /**
12497            * @ngdoc method
12498            * @name $logProvider#debugEnabled
12499            * @description
12500            * @param {boolean=} flag enable or disable debug level messages
12501            * @returns {*} current value if used as getter or itself (chaining) if used as setter
12502            */
12503           this.debugEnabled = function(flag) {
12504             if (isDefined(flag)) {
12505               debug = flag;
12506             return this;
12507             } else {
12508               return debug;
12509             }
12510           };
12511
12512           this.$get = ['$window', function($window) {
12513             return {
12514               /**
12515                * @ngdoc method
12516                * @name $log#log
12517                *
12518                * @description
12519                * Write a log message
12520                */
12521               log: consoleLog('log'),
12522
12523               /**
12524                * @ngdoc method
12525                * @name $log#info
12526                *
12527                * @description
12528                * Write an information message
12529                */
12530               info: consoleLog('info'),
12531
12532               /**
12533                * @ngdoc method
12534                * @name $log#warn
12535                *
12536                * @description
12537                * Write a warning message
12538                */
12539               warn: consoleLog('warn'),
12540
12541               /**
12542                * @ngdoc method
12543                * @name $log#error
12544                *
12545                * @description
12546                * Write an error message
12547                */
12548               error: consoleLog('error'),
12549
12550               /**
12551                * @ngdoc method
12552                * @name $log#debug
12553                *
12554                * @description
12555                * Write a debug message
12556                */
12557               debug: (function() {
12558                 var fn = consoleLog('debug');
12559
12560                 return function() {
12561                   if (debug) {
12562                     fn.apply(self, arguments);
12563                   }
12564                 };
12565               }())
12566             };
12567
12568             function formatError(arg) {
12569               if (arg instanceof Error) {
12570                 if (arg.stack) {
12571                   arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
12572                       ? 'Error: ' + arg.message + '\n' + arg.stack
12573                       : arg.stack;
12574                 } else if (arg.sourceURL) {
12575                   arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
12576                 }
12577               }
12578               return arg;
12579             }
12580
12581             function consoleLog(type) {
12582               var console = $window.console || {},
12583                   logFn = console[type] || console.log || noop,
12584                   hasApply = false;
12585
12586               // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
12587               // The reason behind this is that console.log has type "object" in IE8...
12588               try {
12589                 hasApply = !!logFn.apply;
12590               } catch (e) {}
12591
12592               if (hasApply) {
12593                 return function() {
12594                   var args = [];
12595                   forEach(arguments, function(arg) {
12596                     args.push(formatError(arg));
12597                   });
12598                   return logFn.apply(console, args);
12599                 };
12600               }
12601
12602               // we are IE which either doesn't have window.console => this is noop and we do nothing,
12603               // or we are IE where console.log doesn't have apply so we log at least first 2 args
12604               return function(arg1, arg2) {
12605                 logFn(arg1, arg2 == null ? '' : arg2);
12606               };
12607             }
12608           }];
12609         }
12610
12611         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
12612          *     Any commits to this file should be reviewed with security in mind.  *
12613          *   Changes to this file can potentially create security vulnerabilities. *
12614          *          An approval from 2 Core members with history of modifying      *
12615          *                         this file is required.                          *
12616          *                                                                         *
12617          *  Does the change somehow allow for arbitrary javascript to be executed? *
12618          *    Or allows for someone to change the prototype of built-in objects?   *
12619          *     Or gives undesired access to variables likes document or window?    *
12620          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12621
12622         var $parseMinErr = minErr('$parse');
12623
12624         // Sandboxing Angular Expressions
12625         // ------------------------------
12626         // Angular expressions are generally considered safe because these expressions only have direct
12627         // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
12628         // obtaining a reference to native JS functions such as the Function constructor.
12629         //
12630         // As an example, consider the following Angular expression:
12631         //
12632         //   {}.toString.constructor('alert("evil JS code")')
12633         //
12634         // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
12635         // against the expression language, but not to prevent exploits that were enabled by exposing
12636         // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
12637         // practice and therefore we are not even trying to protect against interaction with an object
12638         // explicitly exposed in this way.
12639         //
12640         // In general, it is not possible to access a Window object from an angular expression unless a
12641         // window or some DOM object that has a reference to window is published onto a Scope.
12642         // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
12643         // native objects.
12644         //
12645         // See https://docs.angularjs.org/guide/security
12646
12647
12648         function ensureSafeMemberName(name, fullExpression) {
12649           if (name === "__defineGetter__" || name === "__defineSetter__"
12650               || name === "__lookupGetter__" || name === "__lookupSetter__"
12651               || name === "__proto__") {
12652             throw $parseMinErr('isecfld',
12653                 'Attempting to access a disallowed field in Angular expressions! '
12654                 + 'Expression: {0}', fullExpression);
12655           }
12656           return name;
12657         }
12658
12659         function getStringValue(name, fullExpression) {
12660           // From the JavaScript docs:
12661           // Property names must be strings. This means that non-string objects cannot be used
12662           // as keys in an object. Any non-string object, including a number, is typecasted
12663           // into a string via the toString method.
12664           //
12665           // So, to ensure that we are checking the same `name` that JavaScript would use,
12666           // we cast it to a string, if possible.
12667           // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
12668           // this is, this will handle objects that misbehave.
12669           name = name + '';
12670           if (!isString(name)) {
12671             throw $parseMinErr('iseccst',
12672                 'Cannot convert object to primitive value! '
12673                 + 'Expression: {0}', fullExpression);
12674           }
12675           return name;
12676         }
12677
12678         function ensureSafeObject(obj, fullExpression) {
12679           // nifty check if obj is Function that is fast and works across iframes and other contexts
12680           if (obj) {
12681             if (obj.constructor === obj) {
12682               throw $parseMinErr('isecfn',
12683                   'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12684                   fullExpression);
12685             } else if (// isWindow(obj)
12686                 obj.window === obj) {
12687               throw $parseMinErr('isecwindow',
12688                   'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
12689                   fullExpression);
12690             } else if (// isElement(obj)
12691                 obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
12692               throw $parseMinErr('isecdom',
12693                   'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
12694                   fullExpression);
12695             } else if (// block Object so that we can't get hold of dangerous Object.* methods
12696                 obj === Object) {
12697               throw $parseMinErr('isecobj',
12698                   'Referencing Object in Angular expressions is disallowed! Expression: {0}',
12699                   fullExpression);
12700             }
12701           }
12702           return obj;
12703         }
12704
12705         var CALL = Function.prototype.call;
12706         var APPLY = Function.prototype.apply;
12707         var BIND = Function.prototype.bind;
12708
12709         function ensureSafeFunction(obj, fullExpression) {
12710           if (obj) {
12711             if (obj.constructor === obj) {
12712               throw $parseMinErr('isecfn',
12713                 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12714                 fullExpression);
12715             } else if (obj === CALL || obj === APPLY || obj === BIND) {
12716               throw $parseMinErr('isecff',
12717                 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
12718                 fullExpression);
12719             }
12720           }
12721         }
12722
12723         function ensureSafeAssignContext(obj, fullExpression) {
12724           if (obj) {
12725             if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
12726                 obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
12727               throw $parseMinErr('isecaf',
12728                 'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
12729             }
12730           }
12731         }
12732
12733         var OPERATORS = createMap();
12734         forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
12735         var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
12736
12737
12738         /////////////////////////////////////////
12739
12740
12741         /**
12742          * @constructor
12743          */
12744         var Lexer = function(options) {
12745           this.options = options;
12746         };
12747
12748         Lexer.prototype = {
12749           constructor: Lexer,
12750
12751           lex: function(text) {
12752             this.text = text;
12753             this.index = 0;
12754             this.tokens = [];
12755
12756             while (this.index < this.text.length) {
12757               var ch = this.text.charAt(this.index);
12758               if (ch === '"' || ch === "'") {
12759                 this.readString(ch);
12760               } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
12761                 this.readNumber();
12762               } else if (this.isIdent(ch)) {
12763                 this.readIdent();
12764               } else if (this.is(ch, '(){}[].,;:?')) {
12765                 this.tokens.push({index: this.index, text: ch});
12766                 this.index++;
12767               } else if (this.isWhitespace(ch)) {
12768                 this.index++;
12769               } else {
12770                 var ch2 = ch + this.peek();
12771                 var ch3 = ch2 + this.peek(2);
12772                 var op1 = OPERATORS[ch];
12773                 var op2 = OPERATORS[ch2];
12774                 var op3 = OPERATORS[ch3];
12775                 if (op1 || op2 || op3) {
12776                   var token = op3 ? ch3 : (op2 ? ch2 : ch);
12777                   this.tokens.push({index: this.index, text: token, operator: true});
12778                   this.index += token.length;
12779                 } else {
12780                   this.throwError('Unexpected next character ', this.index, this.index + 1);
12781                 }
12782               }
12783             }
12784             return this.tokens;
12785           },
12786
12787           is: function(ch, chars) {
12788             return chars.indexOf(ch) !== -1;
12789           },
12790
12791           peek: function(i) {
12792             var num = i || 1;
12793             return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
12794           },
12795
12796           isNumber: function(ch) {
12797             return ('0' <= ch && ch <= '9') && typeof ch === "string";
12798           },
12799
12800           isWhitespace: function(ch) {
12801             // IE treats non-breaking space as \u00A0
12802             return (ch === ' ' || ch === '\r' || ch === '\t' ||
12803                     ch === '\n' || ch === '\v' || ch === '\u00A0');
12804           },
12805
12806           isIdent: function(ch) {
12807             return ('a' <= ch && ch <= 'z' ||
12808                     'A' <= ch && ch <= 'Z' ||
12809                     '_' === ch || ch === '$');
12810           },
12811
12812           isExpOperator: function(ch) {
12813             return (ch === '-' || ch === '+' || this.isNumber(ch));
12814           },
12815
12816           throwError: function(error, start, end) {
12817             end = end || this.index;
12818             var colStr = (isDefined(start)
12819                     ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
12820                     : ' ' + end);
12821             throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
12822                 error, colStr, this.text);
12823           },
12824
12825           readNumber: function() {
12826             var number = '';
12827             var start = this.index;
12828             while (this.index < this.text.length) {
12829               var ch = lowercase(this.text.charAt(this.index));
12830               if (ch == '.' || this.isNumber(ch)) {
12831                 number += ch;
12832               } else {
12833                 var peekCh = this.peek();
12834                 if (ch == 'e' && this.isExpOperator(peekCh)) {
12835                   number += ch;
12836                 } else if (this.isExpOperator(ch) &&
12837                     peekCh && this.isNumber(peekCh) &&
12838                     number.charAt(number.length - 1) == 'e') {
12839                   number += ch;
12840                 } else if (this.isExpOperator(ch) &&
12841                     (!peekCh || !this.isNumber(peekCh)) &&
12842                     number.charAt(number.length - 1) == 'e') {
12843                   this.throwError('Invalid exponent');
12844                 } else {
12845                   break;
12846                 }
12847               }
12848               this.index++;
12849             }
12850             this.tokens.push({
12851               index: start,
12852               text: number,
12853               constant: true,
12854               value: Number(number)
12855             });
12856           },
12857
12858           readIdent: function() {
12859             var start = this.index;
12860             while (this.index < this.text.length) {
12861               var ch = this.text.charAt(this.index);
12862               if (!(this.isIdent(ch) || this.isNumber(ch))) {
12863                 break;
12864               }
12865               this.index++;
12866             }
12867             this.tokens.push({
12868               index: start,
12869               text: this.text.slice(start, this.index),
12870               identifier: true
12871             });
12872           },
12873
12874           readString: function(quote) {
12875             var start = this.index;
12876             this.index++;
12877             var string = '';
12878             var rawString = quote;
12879             var escape = false;
12880             while (this.index < this.text.length) {
12881               var ch = this.text.charAt(this.index);
12882               rawString += ch;
12883               if (escape) {
12884                 if (ch === 'u') {
12885                   var hex = this.text.substring(this.index + 1, this.index + 5);
12886                   if (!hex.match(/[\da-f]{4}/i)) {
12887                     this.throwError('Invalid unicode escape [\\u' + hex + ']');
12888                   }
12889                   this.index += 4;
12890                   string += String.fromCharCode(parseInt(hex, 16));
12891                 } else {
12892                   var rep = ESCAPE[ch];
12893                   string = string + (rep || ch);
12894                 }
12895                 escape = false;
12896               } else if (ch === '\\') {
12897                 escape = true;
12898               } else if (ch === quote) {
12899                 this.index++;
12900                 this.tokens.push({
12901                   index: start,
12902                   text: rawString,
12903                   constant: true,
12904                   value: string
12905                 });
12906                 return;
12907               } else {
12908                 string += ch;
12909               }
12910               this.index++;
12911             }
12912             this.throwError('Unterminated quote', start);
12913           }
12914         };
12915
12916         var AST = function(lexer, options) {
12917           this.lexer = lexer;
12918           this.options = options;
12919         };
12920
12921         AST.Program = 'Program';
12922         AST.ExpressionStatement = 'ExpressionStatement';
12923         AST.AssignmentExpression = 'AssignmentExpression';
12924         AST.ConditionalExpression = 'ConditionalExpression';
12925         AST.LogicalExpression = 'LogicalExpression';
12926         AST.BinaryExpression = 'BinaryExpression';
12927         AST.UnaryExpression = 'UnaryExpression';
12928         AST.CallExpression = 'CallExpression';
12929         AST.MemberExpression = 'MemberExpression';
12930         AST.Identifier = 'Identifier';
12931         AST.Literal = 'Literal';
12932         AST.ArrayExpression = 'ArrayExpression';
12933         AST.Property = 'Property';
12934         AST.ObjectExpression = 'ObjectExpression';
12935         AST.ThisExpression = 'ThisExpression';
12936
12937         // Internal use only
12938         AST.NGValueParameter = 'NGValueParameter';
12939
12940         AST.prototype = {
12941           ast: function(text) {
12942             this.text = text;
12943             this.tokens = this.lexer.lex(text);
12944
12945             var value = this.program();
12946
12947             if (this.tokens.length !== 0) {
12948               this.throwError('is an unexpected token', this.tokens[0]);
12949             }
12950
12951             return value;
12952           },
12953
12954           program: function() {
12955             var body = [];
12956             while (true) {
12957               if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
12958                 body.push(this.expressionStatement());
12959               if (!this.expect(';')) {
12960                 return { type: AST.Program, body: body};
12961               }
12962             }
12963           },
12964
12965           expressionStatement: function() {
12966             return { type: AST.ExpressionStatement, expression: this.filterChain() };
12967           },
12968
12969           filterChain: function() {
12970             var left = this.expression();
12971             var token;
12972             while ((token = this.expect('|'))) {
12973               left = this.filter(left);
12974             }
12975             return left;
12976           },
12977
12978           expression: function() {
12979             return this.assignment();
12980           },
12981
12982           assignment: function() {
12983             var result = this.ternary();
12984             if (this.expect('=')) {
12985               result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
12986             }
12987             return result;
12988           },
12989
12990           ternary: function() {
12991             var test = this.logicalOR();
12992             var alternate;
12993             var consequent;
12994             if (this.expect('?')) {
12995               alternate = this.expression();
12996               if (this.consume(':')) {
12997                 consequent = this.expression();
12998                 return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
12999               }
13000             }
13001             return test;
13002           },
13003
13004           logicalOR: function() {
13005             var left = this.logicalAND();
13006             while (this.expect('||')) {
13007               left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
13008             }
13009             return left;
13010           },
13011
13012           logicalAND: function() {
13013             var left = this.equality();
13014             while (this.expect('&&')) {
13015               left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
13016             }
13017             return left;
13018           },
13019
13020           equality: function() {
13021             var left = this.relational();
13022             var token;
13023             while ((token = this.expect('==','!=','===','!=='))) {
13024               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
13025             }
13026             return left;
13027           },
13028
13029           relational: function() {
13030             var left = this.additive();
13031             var token;
13032             while ((token = this.expect('<', '>', '<=', '>='))) {
13033               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
13034             }
13035             return left;
13036           },
13037
13038           additive: function() {
13039             var left = this.multiplicative();
13040             var token;
13041             while ((token = this.expect('+','-'))) {
13042               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
13043             }
13044             return left;
13045           },
13046
13047           multiplicative: function() {
13048             var left = this.unary();
13049             var token;
13050             while ((token = this.expect('*','/','%'))) {
13051               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
13052             }
13053             return left;
13054           },
13055
13056           unary: function() {
13057             var token;
13058             if ((token = this.expect('+', '-', '!'))) {
13059               return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
13060             } else {
13061               return this.primary();
13062             }
13063           },
13064
13065           primary: function() {
13066             var primary;
13067             if (this.expect('(')) {
13068               primary = this.filterChain();
13069               this.consume(')');
13070             } else if (this.expect('[')) {
13071               primary = this.arrayDeclaration();
13072             } else if (this.expect('{')) {
13073               primary = this.object();
13074             } else if (this.constants.hasOwnProperty(this.peek().text)) {
13075               primary = copy(this.constants[this.consume().text]);
13076             } else if (this.peek().identifier) {
13077               primary = this.identifier();
13078             } else if (this.peek().constant) {
13079               primary = this.constant();
13080             } else {
13081               this.throwError('not a primary expression', this.peek());
13082             }
13083
13084             var next;
13085             while ((next = this.expect('(', '[', '.'))) {
13086               if (next.text === '(') {
13087                 primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
13088                 this.consume(')');
13089               } else if (next.text === '[') {
13090                 primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
13091                 this.consume(']');
13092               } else if (next.text === '.') {
13093                 primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
13094               } else {
13095                 this.throwError('IMPOSSIBLE');
13096               }
13097             }
13098             return primary;
13099           },
13100
13101           filter: function(baseExpression) {
13102             var args = [baseExpression];
13103             var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
13104
13105             while (this.expect(':')) {
13106               args.push(this.expression());
13107             }
13108
13109             return result;
13110           },
13111
13112           parseArguments: function() {
13113             var args = [];
13114             if (this.peekToken().text !== ')') {
13115               do {
13116                 args.push(this.expression());
13117               } while (this.expect(','));
13118             }
13119             return args;
13120           },
13121
13122           identifier: function() {
13123             var token = this.consume();
13124             if (!token.identifier) {
13125               this.throwError('is not a valid identifier', token);
13126             }
13127             return { type: AST.Identifier, name: token.text };
13128           },
13129
13130           constant: function() {
13131             // TODO check that it is a constant
13132             return { type: AST.Literal, value: this.consume().value };
13133           },
13134
13135           arrayDeclaration: function() {
13136             var elements = [];
13137             if (this.peekToken().text !== ']') {
13138               do {
13139                 if (this.peek(']')) {
13140                   // Support trailing commas per ES5.1.
13141                   break;
13142                 }
13143                 elements.push(this.expression());
13144               } while (this.expect(','));
13145             }
13146             this.consume(']');
13147
13148             return { type: AST.ArrayExpression, elements: elements };
13149           },
13150
13151           object: function() {
13152             var properties = [], property;
13153             if (this.peekToken().text !== '}') {
13154               do {
13155                 if (this.peek('}')) {
13156                   // Support trailing commas per ES5.1.
13157                   break;
13158                 }
13159                 property = {type: AST.Property, kind: 'init'};
13160                 if (this.peek().constant) {
13161                   property.key = this.constant();
13162                 } else if (this.peek().identifier) {
13163                   property.key = this.identifier();
13164                 } else {
13165                   this.throwError("invalid key", this.peek());
13166                 }
13167                 this.consume(':');
13168                 property.value = this.expression();
13169                 properties.push(property);
13170               } while (this.expect(','));
13171             }
13172             this.consume('}');
13173
13174             return {type: AST.ObjectExpression, properties: properties };
13175           },
13176
13177           throwError: function(msg, token) {
13178             throw $parseMinErr('syntax',
13179                 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
13180                   token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
13181           },
13182
13183           consume: function(e1) {
13184             if (this.tokens.length === 0) {
13185               throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
13186             }
13187
13188             var token = this.expect(e1);
13189             if (!token) {
13190               this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
13191             }
13192             return token;
13193           },
13194
13195           peekToken: function() {
13196             if (this.tokens.length === 0) {
13197               throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
13198             }
13199             return this.tokens[0];
13200           },
13201
13202           peek: function(e1, e2, e3, e4) {
13203             return this.peekAhead(0, e1, e2, e3, e4);
13204           },
13205
13206           peekAhead: function(i, e1, e2, e3, e4) {
13207             if (this.tokens.length > i) {
13208               var token = this.tokens[i];
13209               var t = token.text;
13210               if (t === e1 || t === e2 || t === e3 || t === e4 ||
13211                   (!e1 && !e2 && !e3 && !e4)) {
13212                 return token;
13213               }
13214             }
13215             return false;
13216           },
13217
13218           expect: function(e1, e2, e3, e4) {
13219             var token = this.peek(e1, e2, e3, e4);
13220             if (token) {
13221               this.tokens.shift();
13222               return token;
13223             }
13224             return false;
13225           },
13226
13227
13228           /* `undefined` is not a constant, it is an identifier,
13229            * but using it as an identifier is not supported
13230            */
13231           constants: {
13232             'true': { type: AST.Literal, value: true },
13233             'false': { type: AST.Literal, value: false },
13234             'null': { type: AST.Literal, value: null },
13235             'undefined': {type: AST.Literal, value: undefined },
13236             'this': {type: AST.ThisExpression }
13237           }
13238         };
13239
13240         function ifDefined(v, d) {
13241           return typeof v !== 'undefined' ? v : d;
13242         }
13243
13244         function plusFn(l, r) {
13245           if (typeof l === 'undefined') return r;
13246           if (typeof r === 'undefined') return l;
13247           return l + r;
13248         }
13249
13250         function isStateless($filter, filterName) {
13251           var fn = $filter(filterName);
13252           return !fn.$stateful;
13253         }
13254
13255         function findConstantAndWatchExpressions(ast, $filter) {
13256           var allConstants;
13257           var argsToWatch;
13258           switch (ast.type) {
13259           case AST.Program:
13260             allConstants = true;
13261             forEach(ast.body, function(expr) {
13262               findConstantAndWatchExpressions(expr.expression, $filter);
13263               allConstants = allConstants && expr.expression.constant;
13264             });
13265             ast.constant = allConstants;
13266             break;
13267           case AST.Literal:
13268             ast.constant = true;
13269             ast.toWatch = [];
13270             break;
13271           case AST.UnaryExpression:
13272             findConstantAndWatchExpressions(ast.argument, $filter);
13273             ast.constant = ast.argument.constant;
13274             ast.toWatch = ast.argument.toWatch;
13275             break;
13276           case AST.BinaryExpression:
13277             findConstantAndWatchExpressions(ast.left, $filter);
13278             findConstantAndWatchExpressions(ast.right, $filter);
13279             ast.constant = ast.left.constant && ast.right.constant;
13280             ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
13281             break;
13282           case AST.LogicalExpression:
13283             findConstantAndWatchExpressions(ast.left, $filter);
13284             findConstantAndWatchExpressions(ast.right, $filter);
13285             ast.constant = ast.left.constant && ast.right.constant;
13286             ast.toWatch = ast.constant ? [] : [ast];
13287             break;
13288           case AST.ConditionalExpression:
13289             findConstantAndWatchExpressions(ast.test, $filter);
13290             findConstantAndWatchExpressions(ast.alternate, $filter);
13291             findConstantAndWatchExpressions(ast.consequent, $filter);
13292             ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
13293             ast.toWatch = ast.constant ? [] : [ast];
13294             break;
13295           case AST.Identifier:
13296             ast.constant = false;
13297             ast.toWatch = [ast];
13298             break;
13299           case AST.MemberExpression:
13300             findConstantAndWatchExpressions(ast.object, $filter);
13301             if (ast.computed) {
13302               findConstantAndWatchExpressions(ast.property, $filter);
13303             }
13304             ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
13305             ast.toWatch = [ast];
13306             break;
13307           case AST.CallExpression:
13308             allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
13309             argsToWatch = [];
13310             forEach(ast.arguments, function(expr) {
13311               findConstantAndWatchExpressions(expr, $filter);
13312               allConstants = allConstants && expr.constant;
13313               if (!expr.constant) {
13314                 argsToWatch.push.apply(argsToWatch, expr.toWatch);
13315               }
13316             });
13317             ast.constant = allConstants;
13318             ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
13319             break;
13320           case AST.AssignmentExpression:
13321             findConstantAndWatchExpressions(ast.left, $filter);
13322             findConstantAndWatchExpressions(ast.right, $filter);
13323             ast.constant = ast.left.constant && ast.right.constant;
13324             ast.toWatch = [ast];
13325             break;
13326           case AST.ArrayExpression:
13327             allConstants = true;
13328             argsToWatch = [];
13329             forEach(ast.elements, function(expr) {
13330               findConstantAndWatchExpressions(expr, $filter);
13331               allConstants = allConstants && expr.constant;
13332               if (!expr.constant) {
13333                 argsToWatch.push.apply(argsToWatch, expr.toWatch);
13334               }
13335             });
13336             ast.constant = allConstants;
13337             ast.toWatch = argsToWatch;
13338             break;
13339           case AST.ObjectExpression:
13340             allConstants = true;
13341             argsToWatch = [];
13342             forEach(ast.properties, function(property) {
13343               findConstantAndWatchExpressions(property.value, $filter);
13344               allConstants = allConstants && property.value.constant;
13345               if (!property.value.constant) {
13346                 argsToWatch.push.apply(argsToWatch, property.value.toWatch);
13347               }
13348             });
13349             ast.constant = allConstants;
13350             ast.toWatch = argsToWatch;
13351             break;
13352           case AST.ThisExpression:
13353             ast.constant = false;
13354             ast.toWatch = [];
13355             break;
13356           }
13357         }
13358
13359         function getInputs(body) {
13360           if (body.length != 1) return;
13361           var lastExpression = body[0].expression;
13362           var candidate = lastExpression.toWatch;
13363           if (candidate.length !== 1) return candidate;
13364           return candidate[0] !== lastExpression ? candidate : undefined;
13365         }
13366
13367         function isAssignable(ast) {
13368           return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
13369         }
13370
13371         function assignableAST(ast) {
13372           if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
13373             return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
13374           }
13375         }
13376
13377         function isLiteral(ast) {
13378           return ast.body.length === 0 ||
13379               ast.body.length === 1 && (
13380               ast.body[0].expression.type === AST.Literal ||
13381               ast.body[0].expression.type === AST.ArrayExpression ||
13382               ast.body[0].expression.type === AST.ObjectExpression);
13383         }
13384
13385         function isConstant(ast) {
13386           return ast.constant;
13387         }
13388
13389         function ASTCompiler(astBuilder, $filter) {
13390           this.astBuilder = astBuilder;
13391           this.$filter = $filter;
13392         }
13393
13394         ASTCompiler.prototype = {
13395           compile: function(expression, expensiveChecks) {
13396             var self = this;
13397             var ast = this.astBuilder.ast(expression);
13398             this.state = {
13399               nextId: 0,
13400               filters: {},
13401               expensiveChecks: expensiveChecks,
13402               fn: {vars: [], body: [], own: {}},
13403               assign: {vars: [], body: [], own: {}},
13404               inputs: []
13405             };
13406             findConstantAndWatchExpressions(ast, self.$filter);
13407             var extra = '';
13408             var assignable;
13409             this.stage = 'assign';
13410             if ((assignable = assignableAST(ast))) {
13411               this.state.computing = 'assign';
13412               var result = this.nextId();
13413               this.recurse(assignable, result);
13414               this.return_(result);
13415               extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
13416             }
13417             var toWatch = getInputs(ast.body);
13418             self.stage = 'inputs';
13419             forEach(toWatch, function(watch, key) {
13420               var fnKey = 'fn' + key;
13421               self.state[fnKey] = {vars: [], body: [], own: {}};
13422               self.state.computing = fnKey;
13423               var intoId = self.nextId();
13424               self.recurse(watch, intoId);
13425               self.return_(intoId);
13426               self.state.inputs.push(fnKey);
13427               watch.watchId = key;
13428             });
13429             this.state.computing = 'fn';
13430             this.stage = 'main';
13431             this.recurse(ast);
13432             var fnString =
13433               // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
13434               // This is a workaround for this until we do a better job at only removing the prefix only when we should.
13435               '"' + this.USE + ' ' + this.STRICT + '";\n' +
13436               this.filterPrefix() +
13437               'var fn=' + this.generateFunction('fn', 's,l,a,i') +
13438               extra +
13439               this.watchFns() +
13440               'return fn;';
13441
13442             /* jshint -W054 */
13443             var fn = (new Function('$filter',
13444                 'ensureSafeMemberName',
13445                 'ensureSafeObject',
13446                 'ensureSafeFunction',
13447                 'getStringValue',
13448                 'ensureSafeAssignContext',
13449                 'ifDefined',
13450                 'plus',
13451                 'text',
13452                 fnString))(
13453                   this.$filter,
13454                   ensureSafeMemberName,
13455                   ensureSafeObject,
13456                   ensureSafeFunction,
13457                   getStringValue,
13458                   ensureSafeAssignContext,
13459                   ifDefined,
13460                   plusFn,
13461                   expression);
13462             /* jshint +W054 */
13463             this.state = this.stage = undefined;
13464             fn.literal = isLiteral(ast);
13465             fn.constant = isConstant(ast);
13466             return fn;
13467           },
13468
13469           USE: 'use',
13470
13471           STRICT: 'strict',
13472
13473           watchFns: function() {
13474             var result = [];
13475             var fns = this.state.inputs;
13476             var self = this;
13477             forEach(fns, function(name) {
13478               result.push('var ' + name + '=' + self.generateFunction(name, 's'));
13479             });
13480             if (fns.length) {
13481               result.push('fn.inputs=[' + fns.join(',') + '];');
13482             }
13483             return result.join('');
13484           },
13485
13486           generateFunction: function(name, params) {
13487             return 'function(' + params + '){' +
13488                 this.varsPrefix(name) +
13489                 this.body(name) +
13490                 '};';
13491           },
13492
13493           filterPrefix: function() {
13494             var parts = [];
13495             var self = this;
13496             forEach(this.state.filters, function(id, filter) {
13497               parts.push(id + '=$filter(' + self.escape(filter) + ')');
13498             });
13499             if (parts.length) return 'var ' + parts.join(',') + ';';
13500             return '';
13501           },
13502
13503           varsPrefix: function(section) {
13504             return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
13505           },
13506
13507           body: function(section) {
13508             return this.state[section].body.join('');
13509           },
13510
13511           recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13512             var left, right, self = this, args, expression;
13513             recursionFn = recursionFn || noop;
13514             if (!skipWatchIdCheck && isDefined(ast.watchId)) {
13515               intoId = intoId || this.nextId();
13516               this.if_('i',
13517                 this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
13518                 this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
13519               );
13520               return;
13521             }
13522             switch (ast.type) {
13523             case AST.Program:
13524               forEach(ast.body, function(expression, pos) {
13525                 self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
13526                 if (pos !== ast.body.length - 1) {
13527                   self.current().body.push(right, ';');
13528                 } else {
13529                   self.return_(right);
13530                 }
13531               });
13532               break;
13533             case AST.Literal:
13534               expression = this.escape(ast.value);
13535               this.assign(intoId, expression);
13536               recursionFn(expression);
13537               break;
13538             case AST.UnaryExpression:
13539               this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
13540               expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
13541               this.assign(intoId, expression);
13542               recursionFn(expression);
13543               break;
13544             case AST.BinaryExpression:
13545               this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
13546               this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
13547               if (ast.operator === '+') {
13548                 expression = this.plus(left, right);
13549               } else if (ast.operator === '-') {
13550                 expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
13551               } else {
13552                 expression = '(' + left + ')' + ast.operator + '(' + right + ')';
13553               }
13554               this.assign(intoId, expression);
13555               recursionFn(expression);
13556               break;
13557             case AST.LogicalExpression:
13558               intoId = intoId || this.nextId();
13559               self.recurse(ast.left, intoId);
13560               self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
13561               recursionFn(intoId);
13562               break;
13563             case AST.ConditionalExpression:
13564               intoId = intoId || this.nextId();
13565               self.recurse(ast.test, intoId);
13566               self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
13567               recursionFn(intoId);
13568               break;
13569             case AST.Identifier:
13570               intoId = intoId || this.nextId();
13571               if (nameId) {
13572                 nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
13573                 nameId.computed = false;
13574                 nameId.name = ast.name;
13575               }
13576               ensureSafeMemberName(ast.name);
13577               self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
13578                 function() {
13579                   self.if_(self.stage === 'inputs' || 's', function() {
13580                     if (create && create !== 1) {
13581                       self.if_(
13582                         self.not(self.nonComputedMember('s', ast.name)),
13583                         self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
13584                     }
13585                     self.assign(intoId, self.nonComputedMember('s', ast.name));
13586                   });
13587                 }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
13588                 );
13589               if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
13590                 self.addEnsureSafeObject(intoId);
13591               }
13592               recursionFn(intoId);
13593               break;
13594             case AST.MemberExpression:
13595               left = nameId && (nameId.context = this.nextId()) || this.nextId();
13596               intoId = intoId || this.nextId();
13597               self.recurse(ast.object, left, undefined, function() {
13598                 self.if_(self.notNull(left), function() {
13599                   if (ast.computed) {
13600                     right = self.nextId();
13601                     self.recurse(ast.property, right);
13602                     self.getStringValue(right);
13603                     self.addEnsureSafeMemberName(right);
13604                     if (create && create !== 1) {
13605                       self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
13606                     }
13607                     expression = self.ensureSafeObject(self.computedMember(left, right));
13608                     self.assign(intoId, expression);
13609                     if (nameId) {
13610                       nameId.computed = true;
13611                       nameId.name = right;
13612                     }
13613                   } else {
13614                     ensureSafeMemberName(ast.property.name);
13615                     if (create && create !== 1) {
13616                       self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
13617                     }
13618                     expression = self.nonComputedMember(left, ast.property.name);
13619                     if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
13620                       expression = self.ensureSafeObject(expression);
13621                     }
13622                     self.assign(intoId, expression);
13623                     if (nameId) {
13624                       nameId.computed = false;
13625                       nameId.name = ast.property.name;
13626                     }
13627                   }
13628                 }, function() {
13629                   self.assign(intoId, 'undefined');
13630                 });
13631                 recursionFn(intoId);
13632               }, !!create);
13633               break;
13634             case AST.CallExpression:
13635               intoId = intoId || this.nextId();
13636               if (ast.filter) {
13637                 right = self.filter(ast.callee.name);
13638                 args = [];
13639                 forEach(ast.arguments, function(expr) {
13640                   var argument = self.nextId();
13641                   self.recurse(expr, argument);
13642                   args.push(argument);
13643                 });
13644                 expression = right + '(' + args.join(',') + ')';
13645                 self.assign(intoId, expression);
13646                 recursionFn(intoId);
13647               } else {
13648                 right = self.nextId();
13649                 left = {};
13650                 args = [];
13651                 self.recurse(ast.callee, right, left, function() {
13652                   self.if_(self.notNull(right), function() {
13653                     self.addEnsureSafeFunction(right);
13654                     forEach(ast.arguments, function(expr) {
13655                       self.recurse(expr, self.nextId(), undefined, function(argument) {
13656                         args.push(self.ensureSafeObject(argument));
13657                       });
13658                     });
13659                     if (left.name) {
13660                       if (!self.state.expensiveChecks) {
13661                         self.addEnsureSafeObject(left.context);
13662                       }
13663                       expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
13664                     } else {
13665                       expression = right + '(' + args.join(',') + ')';
13666                     }
13667                     expression = self.ensureSafeObject(expression);
13668                     self.assign(intoId, expression);
13669                   }, function() {
13670                     self.assign(intoId, 'undefined');
13671                   });
13672                   recursionFn(intoId);
13673                 });
13674               }
13675               break;
13676             case AST.AssignmentExpression:
13677               right = this.nextId();
13678               left = {};
13679               if (!isAssignable(ast.left)) {
13680                 throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
13681               }
13682               this.recurse(ast.left, undefined, left, function() {
13683                 self.if_(self.notNull(left.context), function() {
13684                   self.recurse(ast.right, right);
13685                   self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
13686                   self.addEnsureSafeAssignContext(left.context);
13687                   expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
13688                   self.assign(intoId, expression);
13689                   recursionFn(intoId || expression);
13690                 });
13691               }, 1);
13692               break;
13693             case AST.ArrayExpression:
13694               args = [];
13695               forEach(ast.elements, function(expr) {
13696                 self.recurse(expr, self.nextId(), undefined, function(argument) {
13697                   args.push(argument);
13698                 });
13699               });
13700               expression = '[' + args.join(',') + ']';
13701               this.assign(intoId, expression);
13702               recursionFn(expression);
13703               break;
13704             case AST.ObjectExpression:
13705               args = [];
13706               forEach(ast.properties, function(property) {
13707                 self.recurse(property.value, self.nextId(), undefined, function(expr) {
13708                   args.push(self.escape(
13709                       property.key.type === AST.Identifier ? property.key.name :
13710                         ('' + property.key.value)) +
13711                       ':' + expr);
13712                 });
13713               });
13714               expression = '{' + args.join(',') + '}';
13715               this.assign(intoId, expression);
13716               recursionFn(expression);
13717               break;
13718             case AST.ThisExpression:
13719               this.assign(intoId, 's');
13720               recursionFn('s');
13721               break;
13722             case AST.NGValueParameter:
13723               this.assign(intoId, 'v');
13724               recursionFn('v');
13725               break;
13726             }
13727           },
13728
13729           getHasOwnProperty: function(element, property) {
13730             var key = element + '.' + property;
13731             var own = this.current().own;
13732             if (!own.hasOwnProperty(key)) {
13733               own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
13734             }
13735             return own[key];
13736           },
13737
13738           assign: function(id, value) {
13739             if (!id) return;
13740             this.current().body.push(id, '=', value, ';');
13741             return id;
13742           },
13743
13744           filter: function(filterName) {
13745             if (!this.state.filters.hasOwnProperty(filterName)) {
13746               this.state.filters[filterName] = this.nextId(true);
13747             }
13748             return this.state.filters[filterName];
13749           },
13750
13751           ifDefined: function(id, defaultValue) {
13752             return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
13753           },
13754
13755           plus: function(left, right) {
13756             return 'plus(' + left + ',' + right + ')';
13757           },
13758
13759           return_: function(id) {
13760             this.current().body.push('return ', id, ';');
13761           },
13762
13763           if_: function(test, alternate, consequent) {
13764             if (test === true) {
13765               alternate();
13766             } else {
13767               var body = this.current().body;
13768               body.push('if(', test, '){');
13769               alternate();
13770               body.push('}');
13771               if (consequent) {
13772                 body.push('else{');
13773                 consequent();
13774                 body.push('}');
13775               }
13776             }
13777           },
13778
13779           not: function(expression) {
13780             return '!(' + expression + ')';
13781           },
13782
13783           notNull: function(expression) {
13784             return expression + '!=null';
13785           },
13786
13787           nonComputedMember: function(left, right) {
13788             return left + '.' + right;
13789           },
13790
13791           computedMember: function(left, right) {
13792             return left + '[' + right + ']';
13793           },
13794
13795           member: function(left, right, computed) {
13796             if (computed) return this.computedMember(left, right);
13797             return this.nonComputedMember(left, right);
13798           },
13799
13800           addEnsureSafeObject: function(item) {
13801             this.current().body.push(this.ensureSafeObject(item), ';');
13802           },
13803
13804           addEnsureSafeMemberName: function(item) {
13805             this.current().body.push(this.ensureSafeMemberName(item), ';');
13806           },
13807
13808           addEnsureSafeFunction: function(item) {
13809             this.current().body.push(this.ensureSafeFunction(item), ';');
13810           },
13811
13812           addEnsureSafeAssignContext: function(item) {
13813             this.current().body.push(this.ensureSafeAssignContext(item), ';');
13814           },
13815
13816           ensureSafeObject: function(item) {
13817             return 'ensureSafeObject(' + item + ',text)';
13818           },
13819
13820           ensureSafeMemberName: function(item) {
13821             return 'ensureSafeMemberName(' + item + ',text)';
13822           },
13823
13824           ensureSafeFunction: function(item) {
13825             return 'ensureSafeFunction(' + item + ',text)';
13826           },
13827
13828           getStringValue: function(item) {
13829             this.assign(item, 'getStringValue(' + item + ',text)');
13830           },
13831
13832           ensureSafeAssignContext: function(item) {
13833             return 'ensureSafeAssignContext(' + item + ',text)';
13834           },
13835
13836           lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13837             var self = this;
13838             return function() {
13839               self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
13840             };
13841           },
13842
13843           lazyAssign: function(id, value) {
13844             var self = this;
13845             return function() {
13846               self.assign(id, value);
13847             };
13848           },
13849
13850           stringEscapeRegex: /[^ a-zA-Z0-9]/g,
13851
13852           stringEscapeFn: function(c) {
13853             return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
13854           },
13855
13856           escape: function(value) {
13857             if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
13858             if (isNumber(value)) return value.toString();
13859             if (value === true) return 'true';
13860             if (value === false) return 'false';
13861             if (value === null) return 'null';
13862             if (typeof value === 'undefined') return 'undefined';
13863
13864             throw $parseMinErr('esc', 'IMPOSSIBLE');
13865           },
13866
13867           nextId: function(skip, init) {
13868             var id = 'v' + (this.state.nextId++);
13869             if (!skip) {
13870               this.current().vars.push(id + (init ? '=' + init : ''));
13871             }
13872             return id;
13873           },
13874
13875           current: function() {
13876             return this.state[this.state.computing];
13877           }
13878         };
13879
13880
13881         function ASTInterpreter(astBuilder, $filter) {
13882           this.astBuilder = astBuilder;
13883           this.$filter = $filter;
13884         }
13885
13886         ASTInterpreter.prototype = {
13887           compile: function(expression, expensiveChecks) {
13888             var self = this;
13889             var ast = this.astBuilder.ast(expression);
13890             this.expression = expression;
13891             this.expensiveChecks = expensiveChecks;
13892             findConstantAndWatchExpressions(ast, self.$filter);
13893             var assignable;
13894             var assign;
13895             if ((assignable = assignableAST(ast))) {
13896               assign = this.recurse(assignable);
13897             }
13898             var toWatch = getInputs(ast.body);
13899             var inputs;
13900             if (toWatch) {
13901               inputs = [];
13902               forEach(toWatch, function(watch, key) {
13903                 var input = self.recurse(watch);
13904                 watch.input = input;
13905                 inputs.push(input);
13906                 watch.watchId = key;
13907               });
13908             }
13909             var expressions = [];
13910             forEach(ast.body, function(expression) {
13911               expressions.push(self.recurse(expression.expression));
13912             });
13913             var fn = ast.body.length === 0 ? function() {} :
13914                      ast.body.length === 1 ? expressions[0] :
13915                      function(scope, locals) {
13916                        var lastValue;
13917                        forEach(expressions, function(exp) {
13918                          lastValue = exp(scope, locals);
13919                        });
13920                        return lastValue;
13921                      };
13922             if (assign) {
13923               fn.assign = function(scope, value, locals) {
13924                 return assign(scope, locals, value);
13925               };
13926             }
13927             if (inputs) {
13928               fn.inputs = inputs;
13929             }
13930             fn.literal = isLiteral(ast);
13931             fn.constant = isConstant(ast);
13932             return fn;
13933           },
13934
13935           recurse: function(ast, context, create) {
13936             var left, right, self = this, args, expression;
13937             if (ast.input) {
13938               return this.inputs(ast.input, ast.watchId);
13939             }
13940             switch (ast.type) {
13941             case AST.Literal:
13942               return this.value(ast.value, context);
13943             case AST.UnaryExpression:
13944               right = this.recurse(ast.argument);
13945               return this['unary' + ast.operator](right, context);
13946             case AST.BinaryExpression:
13947               left = this.recurse(ast.left);
13948               right = this.recurse(ast.right);
13949               return this['binary' + ast.operator](left, right, context);
13950             case AST.LogicalExpression:
13951               left = this.recurse(ast.left);
13952               right = this.recurse(ast.right);
13953               return this['binary' + ast.operator](left, right, context);
13954             case AST.ConditionalExpression:
13955               return this['ternary?:'](
13956                 this.recurse(ast.test),
13957                 this.recurse(ast.alternate),
13958                 this.recurse(ast.consequent),
13959                 context
13960               );
13961             case AST.Identifier:
13962               ensureSafeMemberName(ast.name, self.expression);
13963               return self.identifier(ast.name,
13964                                      self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
13965                                      context, create, self.expression);
13966             case AST.MemberExpression:
13967               left = this.recurse(ast.object, false, !!create);
13968               if (!ast.computed) {
13969                 ensureSafeMemberName(ast.property.name, self.expression);
13970                 right = ast.property.name;
13971               }
13972               if (ast.computed) right = this.recurse(ast.property);
13973               return ast.computed ?
13974                 this.computedMember(left, right, context, create, self.expression) :
13975                 this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
13976             case AST.CallExpression:
13977               args = [];
13978               forEach(ast.arguments, function(expr) {
13979                 args.push(self.recurse(expr));
13980               });
13981               if (ast.filter) right = this.$filter(ast.callee.name);
13982               if (!ast.filter) right = this.recurse(ast.callee, true);
13983               return ast.filter ?
13984                 function(scope, locals, assign, inputs) {
13985                   var values = [];
13986                   for (var i = 0; i < args.length; ++i) {
13987                     values.push(args[i](scope, locals, assign, inputs));
13988                   }
13989                   var value = right.apply(undefined, values, inputs);
13990                   return context ? {context: undefined, name: undefined, value: value} : value;
13991                 } :
13992                 function(scope, locals, assign, inputs) {
13993                   var rhs = right(scope, locals, assign, inputs);
13994                   var value;
13995                   if (rhs.value != null) {
13996                     ensureSafeObject(rhs.context, self.expression);
13997                     ensureSafeFunction(rhs.value, self.expression);
13998                     var values = [];
13999                     for (var i = 0; i < args.length; ++i) {
14000                       values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
14001                     }
14002                     value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
14003                   }
14004                   return context ? {value: value} : value;
14005                 };
14006             case AST.AssignmentExpression:
14007               left = this.recurse(ast.left, true, 1);
14008               right = this.recurse(ast.right);
14009               return function(scope, locals, assign, inputs) {
14010                 var lhs = left(scope, locals, assign, inputs);
14011                 var rhs = right(scope, locals, assign, inputs);
14012                 ensureSafeObject(lhs.value, self.expression);
14013                 ensureSafeAssignContext(lhs.context);
14014                 lhs.context[lhs.name] = rhs;
14015                 return context ? {value: rhs} : rhs;
14016               };
14017             case AST.ArrayExpression:
14018               args = [];
14019               forEach(ast.elements, function(expr) {
14020                 args.push(self.recurse(expr));
14021               });
14022               return function(scope, locals, assign, inputs) {
14023                 var value = [];
14024                 for (var i = 0; i < args.length; ++i) {
14025                   value.push(args[i](scope, locals, assign, inputs));
14026                 }
14027                 return context ? {value: value} : value;
14028               };
14029             case AST.ObjectExpression:
14030               args = [];
14031               forEach(ast.properties, function(property) {
14032                 args.push({key: property.key.type === AST.Identifier ?
14033                                 property.key.name :
14034                                 ('' + property.key.value),
14035                            value: self.recurse(property.value)
14036                 });
14037               });
14038               return function(scope, locals, assign, inputs) {
14039                 var value = {};
14040                 for (var i = 0; i < args.length; ++i) {
14041                   value[args[i].key] = args[i].value(scope, locals, assign, inputs);
14042                 }
14043                 return context ? {value: value} : value;
14044               };
14045             case AST.ThisExpression:
14046               return function(scope) {
14047                 return context ? {value: scope} : scope;
14048               };
14049             case AST.NGValueParameter:
14050               return function(scope, locals, assign, inputs) {
14051                 return context ? {value: assign} : assign;
14052               };
14053             }
14054           },
14055
14056           'unary+': function(argument, context) {
14057             return function(scope, locals, assign, inputs) {
14058               var arg = argument(scope, locals, assign, inputs);
14059               if (isDefined(arg)) {
14060                 arg = +arg;
14061               } else {
14062                 arg = 0;
14063               }
14064               return context ? {value: arg} : arg;
14065             };
14066           },
14067           'unary-': function(argument, context) {
14068             return function(scope, locals, assign, inputs) {
14069               var arg = argument(scope, locals, assign, inputs);
14070               if (isDefined(arg)) {
14071                 arg = -arg;
14072               } else {
14073                 arg = 0;
14074               }
14075               return context ? {value: arg} : arg;
14076             };
14077           },
14078           'unary!': function(argument, context) {
14079             return function(scope, locals, assign, inputs) {
14080               var arg = !argument(scope, locals, assign, inputs);
14081               return context ? {value: arg} : arg;
14082             };
14083           },
14084           'binary+': function(left, right, context) {
14085             return function(scope, locals, assign, inputs) {
14086               var lhs = left(scope, locals, assign, inputs);
14087               var rhs = right(scope, locals, assign, inputs);
14088               var arg = plusFn(lhs, rhs);
14089               return context ? {value: arg} : arg;
14090             };
14091           },
14092           'binary-': function(left, right, context) {
14093             return function(scope, locals, assign, inputs) {
14094               var lhs = left(scope, locals, assign, inputs);
14095               var rhs = right(scope, locals, assign, inputs);
14096               var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
14097               return context ? {value: arg} : arg;
14098             };
14099           },
14100           'binary*': function(left, right, context) {
14101             return function(scope, locals, assign, inputs) {
14102               var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
14103               return context ? {value: arg} : arg;
14104             };
14105           },
14106           'binary/': function(left, right, context) {
14107             return function(scope, locals, assign, inputs) {
14108               var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
14109               return context ? {value: arg} : arg;
14110             };
14111           },
14112           'binary%': function(left, right, context) {
14113             return function(scope, locals, assign, inputs) {
14114               var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
14115               return context ? {value: arg} : arg;
14116             };
14117           },
14118           'binary===': function(left, right, context) {
14119             return function(scope, locals, assign, inputs) {
14120               var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
14121               return context ? {value: arg} : arg;
14122             };
14123           },
14124           'binary!==': function(left, right, context) {
14125             return function(scope, locals, assign, inputs) {
14126               var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
14127               return context ? {value: arg} : arg;
14128             };
14129           },
14130           'binary==': function(left, right, context) {
14131             return function(scope, locals, assign, inputs) {
14132               var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
14133               return context ? {value: arg} : arg;
14134             };
14135           },
14136           'binary!=': function(left, right, context) {
14137             return function(scope, locals, assign, inputs) {
14138               var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
14139               return context ? {value: arg} : arg;
14140             };
14141           },
14142           'binary<': function(left, right, context) {
14143             return function(scope, locals, assign, inputs) {
14144               var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
14145               return context ? {value: arg} : arg;
14146             };
14147           },
14148           'binary>': function(left, right, context) {
14149             return function(scope, locals, assign, inputs) {
14150               var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
14151               return context ? {value: arg} : arg;
14152             };
14153           },
14154           'binary<=': function(left, right, context) {
14155             return function(scope, locals, assign, inputs) {
14156               var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
14157               return context ? {value: arg} : arg;
14158             };
14159           },
14160           'binary>=': function(left, right, context) {
14161             return function(scope, locals, assign, inputs) {
14162               var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
14163               return context ? {value: arg} : arg;
14164             };
14165           },
14166           'binary&&': function(left, right, context) {
14167             return function(scope, locals, assign, inputs) {
14168               var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
14169               return context ? {value: arg} : arg;
14170             };
14171           },
14172           'binary||': function(left, right, context) {
14173             return function(scope, locals, assign, inputs) {
14174               var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
14175               return context ? {value: arg} : arg;
14176             };
14177           },
14178           'ternary?:': function(test, alternate, consequent, context) {
14179             return function(scope, locals, assign, inputs) {
14180               var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
14181               return context ? {value: arg} : arg;
14182             };
14183           },
14184           value: function(value, context) {
14185             return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
14186           },
14187           identifier: function(name, expensiveChecks, context, create, expression) {
14188             return function(scope, locals, assign, inputs) {
14189               var base = locals && (name in locals) ? locals : scope;
14190               if (create && create !== 1 && base && !(base[name])) {
14191                 base[name] = {};
14192               }
14193               var value = base ? base[name] : undefined;
14194               if (expensiveChecks) {
14195                 ensureSafeObject(value, expression);
14196               }
14197               if (context) {
14198                 return {context: base, name: name, value: value};
14199               } else {
14200                 return value;
14201               }
14202             };
14203           },
14204           computedMember: function(left, right, context, create, expression) {
14205             return function(scope, locals, assign, inputs) {
14206               var lhs = left(scope, locals, assign, inputs);
14207               var rhs;
14208               var value;
14209               if (lhs != null) {
14210                 rhs = right(scope, locals, assign, inputs);
14211                 rhs = getStringValue(rhs);
14212                 ensureSafeMemberName(rhs, expression);
14213                 if (create && create !== 1 && lhs && !(lhs[rhs])) {
14214                   lhs[rhs] = {};
14215                 }
14216                 value = lhs[rhs];
14217                 ensureSafeObject(value, expression);
14218               }
14219               if (context) {
14220                 return {context: lhs, name: rhs, value: value};
14221               } else {
14222                 return value;
14223               }
14224             };
14225           },
14226           nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
14227             return function(scope, locals, assign, inputs) {
14228               var lhs = left(scope, locals, assign, inputs);
14229               if (create && create !== 1 && lhs && !(lhs[right])) {
14230                 lhs[right] = {};
14231               }
14232               var value = lhs != null ? lhs[right] : undefined;
14233               if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
14234                 ensureSafeObject(value, expression);
14235               }
14236               if (context) {
14237                 return {context: lhs, name: right, value: value};
14238               } else {
14239                 return value;
14240               }
14241             };
14242           },
14243           inputs: function(input, watchId) {
14244             return function(scope, value, locals, inputs) {
14245               if (inputs) return inputs[watchId];
14246               return input(scope, value, locals);
14247             };
14248           }
14249         };
14250
14251         /**
14252          * @constructor
14253          */
14254         var Parser = function(lexer, $filter, options) {
14255           this.lexer = lexer;
14256           this.$filter = $filter;
14257           this.options = options;
14258           this.ast = new AST(this.lexer);
14259           this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
14260                                            new ASTCompiler(this.ast, $filter);
14261         };
14262
14263         Parser.prototype = {
14264           constructor: Parser,
14265
14266           parse: function(text) {
14267             return this.astCompiler.compile(text, this.options.expensiveChecks);
14268           }
14269         };
14270
14271         var getterFnCacheDefault = createMap();
14272         var getterFnCacheExpensive = createMap();
14273
14274         function isPossiblyDangerousMemberName(name) {
14275           return name == 'constructor';
14276         }
14277
14278         var objectValueOf = Object.prototype.valueOf;
14279
14280         function getValueOf(value) {
14281           return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
14282         }
14283
14284         ///////////////////////////////////
14285
14286         /**
14287          * @ngdoc service
14288          * @name $parse
14289          * @kind function
14290          *
14291          * @description
14292          *
14293          * Converts Angular {@link guide/expression expression} into a function.
14294          *
14295          * ```js
14296          *   var getter = $parse('user.name');
14297          *   var setter = getter.assign;
14298          *   var context = {user:{name:'angular'}};
14299          *   var locals = {user:{name:'local'}};
14300          *
14301          *   expect(getter(context)).toEqual('angular');
14302          *   setter(context, 'newValue');
14303          *   expect(context.user.name).toEqual('newValue');
14304          *   expect(getter(context, locals)).toEqual('local');
14305          * ```
14306          *
14307          *
14308          * @param {string} expression String expression to compile.
14309          * @returns {function(context, locals)} a function which represents the compiled expression:
14310          *
14311          *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14312          *      are evaluated against (typically a scope object).
14313          *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14314          *      `context`.
14315          *
14316          *    The returned function also has the following properties:
14317          *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
14318          *        literal.
14319          *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
14320          *        constant literals.
14321          *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
14322          *        set to a function to change its value on the given context.
14323          *
14324          */
14325
14326
14327         /**
14328          * @ngdoc provider
14329          * @name $parseProvider
14330          *
14331          * @description
14332          * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
14333          *  service.
14334          */
14335         function $ParseProvider() {
14336           var cacheDefault = createMap();
14337           var cacheExpensive = createMap();
14338
14339           this.$get = ['$filter', function($filter) {
14340             var noUnsafeEval = csp().noUnsafeEval;
14341             var $parseOptions = {
14342                   csp: noUnsafeEval,
14343                   expensiveChecks: false
14344                 },
14345                 $parseOptionsExpensive = {
14346                   csp: noUnsafeEval,
14347                   expensiveChecks: true
14348                 };
14349
14350             return function $parse(exp, interceptorFn, expensiveChecks) {
14351               var parsedExpression, oneTime, cacheKey;
14352
14353               switch (typeof exp) {
14354                 case 'string':
14355                   exp = exp.trim();
14356                   cacheKey = exp;
14357
14358                   var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
14359                   parsedExpression = cache[cacheKey];
14360
14361                   if (!parsedExpression) {
14362                     if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
14363                       oneTime = true;
14364                       exp = exp.substring(2);
14365                     }
14366                     var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
14367                     var lexer = new Lexer(parseOptions);
14368                     var parser = new Parser(lexer, $filter, parseOptions);
14369                     parsedExpression = parser.parse(exp);
14370                     if (parsedExpression.constant) {
14371                       parsedExpression.$$watchDelegate = constantWatchDelegate;
14372                     } else if (oneTime) {
14373                       parsedExpression.$$watchDelegate = parsedExpression.literal ?
14374                           oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
14375                     } else if (parsedExpression.inputs) {
14376                       parsedExpression.$$watchDelegate = inputsWatchDelegate;
14377                     }
14378                     cache[cacheKey] = parsedExpression;
14379                   }
14380                   return addInterceptor(parsedExpression, interceptorFn);
14381
14382                 case 'function':
14383                   return addInterceptor(exp, interceptorFn);
14384
14385                 default:
14386                   return noop;
14387               }
14388             };
14389
14390             function expressionInputDirtyCheck(newValue, oldValueOfValue) {
14391
14392               if (newValue == null || oldValueOfValue == null) { // null/undefined
14393                 return newValue === oldValueOfValue;
14394               }
14395
14396               if (typeof newValue === 'object') {
14397
14398                 // attempt to convert the value to a primitive type
14399                 // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
14400                 //             be cheaply dirty-checked
14401                 newValue = getValueOf(newValue);
14402
14403                 if (typeof newValue === 'object') {
14404                   // objects/arrays are not supported - deep-watching them would be too expensive
14405                   return false;
14406                 }
14407
14408                 // fall-through to the primitive equality check
14409               }
14410
14411               //Primitive or NaN
14412               return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
14413             }
14414
14415             function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
14416               var inputExpressions = parsedExpression.inputs;
14417               var lastResult;
14418
14419               if (inputExpressions.length === 1) {
14420                 var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
14421                 inputExpressions = inputExpressions[0];
14422                 return scope.$watch(function expressionInputWatch(scope) {
14423                   var newInputValue = inputExpressions(scope);
14424                   if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
14425                     lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
14426                     oldInputValueOf = newInputValue && getValueOf(newInputValue);
14427                   }
14428                   return lastResult;
14429                 }, listener, objectEquality, prettyPrintExpression);
14430               }
14431
14432               var oldInputValueOfValues = [];
14433               var oldInputValues = [];
14434               for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14435                 oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
14436                 oldInputValues[i] = null;
14437               }
14438
14439               return scope.$watch(function expressionInputsWatch(scope) {
14440                 var changed = false;
14441
14442                 for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14443                   var newInputValue = inputExpressions[i](scope);
14444                   if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
14445                     oldInputValues[i] = newInputValue;
14446                     oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
14447                   }
14448                 }
14449
14450                 if (changed) {
14451                   lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
14452                 }
14453
14454                 return lastResult;
14455               }, listener, objectEquality, prettyPrintExpression);
14456             }
14457
14458             function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14459               var unwatch, lastValue;
14460               return unwatch = scope.$watch(function oneTimeWatch(scope) {
14461                 return parsedExpression(scope);
14462               }, function oneTimeListener(value, old, scope) {
14463                 lastValue = value;
14464                 if (isFunction(listener)) {
14465                   listener.apply(this, arguments);
14466                 }
14467                 if (isDefined(value)) {
14468                   scope.$$postDigest(function() {
14469                     if (isDefined(lastValue)) {
14470                       unwatch();
14471                     }
14472                   });
14473                 }
14474               }, objectEquality);
14475             }
14476
14477             function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14478               var unwatch, lastValue;
14479               return unwatch = scope.$watch(function oneTimeWatch(scope) {
14480                 return parsedExpression(scope);
14481               }, function oneTimeListener(value, old, scope) {
14482                 lastValue = value;
14483                 if (isFunction(listener)) {
14484                   listener.call(this, value, old, scope);
14485                 }
14486                 if (isAllDefined(value)) {
14487                   scope.$$postDigest(function() {
14488                     if (isAllDefined(lastValue)) unwatch();
14489                   });
14490                 }
14491               }, objectEquality);
14492
14493               function isAllDefined(value) {
14494                 var allDefined = true;
14495                 forEach(value, function(val) {
14496                   if (!isDefined(val)) allDefined = false;
14497                 });
14498                 return allDefined;
14499               }
14500             }
14501
14502             function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14503               var unwatch;
14504               return unwatch = scope.$watch(function constantWatch(scope) {
14505                 return parsedExpression(scope);
14506               }, function constantListener(value, old, scope) {
14507                 if (isFunction(listener)) {
14508                   listener.apply(this, arguments);
14509                 }
14510                 unwatch();
14511               }, objectEquality);
14512             }
14513
14514             function addInterceptor(parsedExpression, interceptorFn) {
14515               if (!interceptorFn) return parsedExpression;
14516               var watchDelegate = parsedExpression.$$watchDelegate;
14517               var useInputs = false;
14518
14519               var regularWatch =
14520                   watchDelegate !== oneTimeLiteralWatchDelegate &&
14521                   watchDelegate !== oneTimeWatchDelegate;
14522
14523               var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
14524                 var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
14525                 return interceptorFn(value, scope, locals);
14526               } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
14527                 var value = parsedExpression(scope, locals, assign, inputs);
14528                 var result = interceptorFn(value, scope, locals);
14529                 // we only return the interceptor's result if the
14530                 // initial value is defined (for bind-once)
14531                 return isDefined(value) ? result : value;
14532               };
14533
14534               // Propagate $$watchDelegates other then inputsWatchDelegate
14535               if (parsedExpression.$$watchDelegate &&
14536                   parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
14537                 fn.$$watchDelegate = parsedExpression.$$watchDelegate;
14538               } else if (!interceptorFn.$stateful) {
14539                 // If there is an interceptor, but no watchDelegate then treat the interceptor like
14540                 // we treat filters - it is assumed to be a pure function unless flagged with $stateful
14541                 fn.$$watchDelegate = inputsWatchDelegate;
14542                 useInputs = !parsedExpression.inputs;
14543                 fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
14544               }
14545
14546               return fn;
14547             }
14548           }];
14549         }
14550
14551         /**
14552          * @ngdoc service
14553          * @name $q
14554          * @requires $rootScope
14555          *
14556          * @description
14557          * A service that helps you run functions asynchronously, and use their return values (or exceptions)
14558          * when they are done processing.
14559          *
14560          * This is an implementation of promises/deferred objects inspired by
14561          * [Kris Kowal's Q](https://github.com/kriskowal/q).
14562          *
14563          * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
14564          * implementations, and the other which resembles ES6 promises to some degree.
14565          *
14566          * # $q constructor
14567          *
14568          * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
14569          * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
14570          * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
14571          *
14572          * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
14573          * available yet.
14574          *
14575          * It can be used like so:
14576          *
14577          * ```js
14578          *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14579          *   // are available in the current lexical scope (they could have been injected or passed in).
14580          *
14581          *   function asyncGreet(name) {
14582          *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
14583          *     return $q(function(resolve, reject) {
14584          *       setTimeout(function() {
14585          *         if (okToGreet(name)) {
14586          *           resolve('Hello, ' + name + '!');
14587          *         } else {
14588          *           reject('Greeting ' + name + ' is not allowed.');
14589          *         }
14590          *       }, 1000);
14591          *     });
14592          *   }
14593          *
14594          *   var promise = asyncGreet('Robin Hood');
14595          *   promise.then(function(greeting) {
14596          *     alert('Success: ' + greeting);
14597          *   }, function(reason) {
14598          *     alert('Failed: ' + reason);
14599          *   });
14600          * ```
14601          *
14602          * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
14603          *
14604          * Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
14605          *
14606          * However, the more traditional CommonJS-style usage is still available, and documented below.
14607          *
14608          * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
14609          * interface for interacting with an object that represents the result of an action that is
14610          * performed asynchronously, and may or may not be finished at any given point in time.
14611          *
14612          * From the perspective of dealing with error handling, deferred and promise APIs are to
14613          * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
14614          *
14615          * ```js
14616          *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14617          *   // are available in the current lexical scope (they could have been injected or passed in).
14618          *
14619          *   function asyncGreet(name) {
14620          *     var deferred = $q.defer();
14621          *
14622          *     setTimeout(function() {
14623          *       deferred.notify('About to greet ' + name + '.');
14624          *
14625          *       if (okToGreet(name)) {
14626          *         deferred.resolve('Hello, ' + name + '!');
14627          *       } else {
14628          *         deferred.reject('Greeting ' + name + ' is not allowed.');
14629          *       }
14630          *     }, 1000);
14631          *
14632          *     return deferred.promise;
14633          *   }
14634          *
14635          *   var promise = asyncGreet('Robin Hood');
14636          *   promise.then(function(greeting) {
14637          *     alert('Success: ' + greeting);
14638          *   }, function(reason) {
14639          *     alert('Failed: ' + reason);
14640          *   }, function(update) {
14641          *     alert('Got notification: ' + update);
14642          *   });
14643          * ```
14644          *
14645          * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
14646          * comes in the way of guarantees that promise and deferred APIs make, see
14647          * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
14648          *
14649          * Additionally the promise api allows for composition that is very hard to do with the
14650          * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
14651          * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
14652          * section on serial or parallel joining of promises.
14653          *
14654          * # The Deferred API
14655          *
14656          * A new instance of deferred is constructed by calling `$q.defer()`.
14657          *
14658          * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
14659          * that can be used for signaling the successful or unsuccessful completion, as well as the status
14660          * of the task.
14661          *
14662          * **Methods**
14663          *
14664          * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
14665          *   constructed via `$q.reject`, the promise will be rejected instead.
14666          * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
14667          *   resolving it with a rejection constructed via `$q.reject`.
14668          * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
14669          *   multiple times before the promise is either resolved or rejected.
14670          *
14671          * **Properties**
14672          *
14673          * - promise – `{Promise}` – promise object associated with this deferred.
14674          *
14675          *
14676          * # The Promise API
14677          *
14678          * A new promise instance is created when a deferred instance is created and can be retrieved by
14679          * calling `deferred.promise`.
14680          *
14681          * The purpose of the promise object is to allow for interested parties to get access to the result
14682          * of the deferred task when it completes.
14683          *
14684          * **Methods**
14685          *
14686          * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
14687          *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
14688          *   as soon as the result is available. The callbacks are called with a single argument: the result
14689          *   or rejection reason. Additionally, the notify callback may be called zero or more times to
14690          *   provide a progress indication, before the promise is resolved or rejected.
14691          *
14692          *   This method *returns a new promise* which is resolved or rejected via the return value of the
14693          *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
14694          *   with the value which is resolved in that promise using
14695          *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
14696          *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
14697          *   resolved or rejected from the notifyCallback method.
14698          *
14699          * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
14700          *
14701          * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
14702          *   but to do so without modifying the final value. This is useful to release resources or do some
14703          *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
14704          *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
14705          *   more information.
14706          *
14707          * # Chaining promises
14708          *
14709          * Because calling the `then` method of a promise returns a new derived promise, it is easily
14710          * possible to create a chain of promises:
14711          *
14712          * ```js
14713          *   promiseB = promiseA.then(function(result) {
14714          *     return result + 1;
14715          *   });
14716          *
14717          *   // promiseB will be resolved immediately after promiseA is resolved and its value
14718          *   // will be the result of promiseA incremented by 1
14719          * ```
14720          *
14721          * It is possible to create chains of any length and since a promise can be resolved with another
14722          * promise (which will defer its resolution further), it is possible to pause/defer resolution of
14723          * the promises at any point in the chain. This makes it possible to implement powerful APIs like
14724          * $http's response interceptors.
14725          *
14726          *
14727          * # Differences between Kris Kowal's Q and $q
14728          *
14729          *  There are two main differences:
14730          *
14731          * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
14732          *   mechanism in angular, which means faster propagation of resolution or rejection into your
14733          *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
14734          * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
14735          *   all the important functionality needed for common async tasks.
14736          *
14737          *  # Testing
14738          *
14739          *  ```js
14740          *    it('should simulate promise', inject(function($q, $rootScope) {
14741          *      var deferred = $q.defer();
14742          *      var promise = deferred.promise;
14743          *      var resolvedValue;
14744          *
14745          *      promise.then(function(value) { resolvedValue = value; });
14746          *      expect(resolvedValue).toBeUndefined();
14747          *
14748          *      // Simulate resolving of promise
14749          *      deferred.resolve(123);
14750          *      // Note that the 'then' function does not get called synchronously.
14751          *      // This is because we want the promise API to always be async, whether or not
14752          *      // it got called synchronously or asynchronously.
14753          *      expect(resolvedValue).toBeUndefined();
14754          *
14755          *      // Propagate promise resolution to 'then' functions using $apply().
14756          *      $rootScope.$apply();
14757          *      expect(resolvedValue).toEqual(123);
14758          *    }));
14759          *  ```
14760          *
14761          * @param {function(function, function)} resolver Function which is responsible for resolving or
14762          *   rejecting the newly created promise. The first parameter is a function which resolves the
14763          *   promise, the second parameter is a function which rejects the promise.
14764          *
14765          * @returns {Promise} The newly created promise.
14766          */
14767         function $QProvider() {
14768
14769           this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
14770             return qFactory(function(callback) {
14771               $rootScope.$evalAsync(callback);
14772             }, $exceptionHandler);
14773           }];
14774         }
14775
14776         function $$QProvider() {
14777           this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
14778             return qFactory(function(callback) {
14779               $browser.defer(callback);
14780             }, $exceptionHandler);
14781           }];
14782         }
14783
14784         /**
14785          * Constructs a promise manager.
14786          *
14787          * @param {function(function)} nextTick Function for executing functions in the next turn.
14788          * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
14789          *     debugging purposes.
14790          * @returns {object} Promise manager.
14791          */
14792         function qFactory(nextTick, exceptionHandler) {
14793           var $qMinErr = minErr('$q', TypeError);
14794           function callOnce(self, resolveFn, rejectFn) {
14795             var called = false;
14796             function wrap(fn) {
14797               return function(value) {
14798                 if (called) return;
14799                 called = true;
14800                 fn.call(self, value);
14801               };
14802             }
14803
14804             return [wrap(resolveFn), wrap(rejectFn)];
14805           }
14806
14807           /**
14808            * @ngdoc method
14809            * @name ng.$q#defer
14810            * @kind function
14811            *
14812            * @description
14813            * Creates a `Deferred` object which represents a task which will finish in the future.
14814            *
14815            * @returns {Deferred} Returns a new instance of deferred.
14816            */
14817           var defer = function() {
14818             return new Deferred();
14819           };
14820
14821           function Promise() {
14822             this.$$state = { status: 0 };
14823           }
14824
14825           extend(Promise.prototype, {
14826             then: function(onFulfilled, onRejected, progressBack) {
14827               if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
14828                 return this;
14829               }
14830               var result = new Deferred();
14831
14832               this.$$state.pending = this.$$state.pending || [];
14833               this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
14834               if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
14835
14836               return result.promise;
14837             },
14838
14839             "catch": function(callback) {
14840               return this.then(null, callback);
14841             },
14842
14843             "finally": function(callback, progressBack) {
14844               return this.then(function(value) {
14845                 return handleCallback(value, true, callback);
14846               }, function(error) {
14847                 return handleCallback(error, false, callback);
14848               }, progressBack);
14849             }
14850           });
14851
14852           //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
14853           function simpleBind(context, fn) {
14854             return function(value) {
14855               fn.call(context, value);
14856             };
14857           }
14858
14859           function processQueue(state) {
14860             var fn, deferred, pending;
14861
14862             pending = state.pending;
14863             state.processScheduled = false;
14864             state.pending = undefined;
14865             for (var i = 0, ii = pending.length; i < ii; ++i) {
14866               deferred = pending[i][0];
14867               fn = pending[i][state.status];
14868               try {
14869                 if (isFunction(fn)) {
14870                   deferred.resolve(fn(state.value));
14871                 } else if (state.status === 1) {
14872                   deferred.resolve(state.value);
14873                 } else {
14874                   deferred.reject(state.value);
14875                 }
14876               } catch (e) {
14877                 deferred.reject(e);
14878                 exceptionHandler(e);
14879               }
14880             }
14881           }
14882
14883           function scheduleProcessQueue(state) {
14884             if (state.processScheduled || !state.pending) return;
14885             state.processScheduled = true;
14886             nextTick(function() { processQueue(state); });
14887           }
14888
14889           function Deferred() {
14890             this.promise = new Promise();
14891             //Necessary to support unbound execution :/
14892             this.resolve = simpleBind(this, this.resolve);
14893             this.reject = simpleBind(this, this.reject);
14894             this.notify = simpleBind(this, this.notify);
14895           }
14896
14897           extend(Deferred.prototype, {
14898             resolve: function(val) {
14899               if (this.promise.$$state.status) return;
14900               if (val === this.promise) {
14901                 this.$$reject($qMinErr(
14902                   'qcycle',
14903                   "Expected promise to be resolved with value other than itself '{0}'",
14904                   val));
14905               } else {
14906                 this.$$resolve(val);
14907               }
14908
14909             },
14910
14911             $$resolve: function(val) {
14912               var then, fns;
14913
14914               fns = callOnce(this, this.$$resolve, this.$$reject);
14915               try {
14916                 if ((isObject(val) || isFunction(val))) then = val && val.then;
14917                 if (isFunction(then)) {
14918                   this.promise.$$state.status = -1;
14919                   then.call(val, fns[0], fns[1], this.notify);
14920                 } else {
14921                   this.promise.$$state.value = val;
14922                   this.promise.$$state.status = 1;
14923                   scheduleProcessQueue(this.promise.$$state);
14924                 }
14925               } catch (e) {
14926                 fns[1](e);
14927                 exceptionHandler(e);
14928               }
14929             },
14930
14931             reject: function(reason) {
14932               if (this.promise.$$state.status) return;
14933               this.$$reject(reason);
14934             },
14935
14936             $$reject: function(reason) {
14937               this.promise.$$state.value = reason;
14938               this.promise.$$state.status = 2;
14939               scheduleProcessQueue(this.promise.$$state);
14940             },
14941
14942             notify: function(progress) {
14943               var callbacks = this.promise.$$state.pending;
14944
14945               if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
14946                 nextTick(function() {
14947                   var callback, result;
14948                   for (var i = 0, ii = callbacks.length; i < ii; i++) {
14949                     result = callbacks[i][0];
14950                     callback = callbacks[i][3];
14951                     try {
14952                       result.notify(isFunction(callback) ? callback(progress) : progress);
14953                     } catch (e) {
14954                       exceptionHandler(e);
14955                     }
14956                   }
14957                 });
14958               }
14959             }
14960           });
14961
14962           /**
14963            * @ngdoc method
14964            * @name $q#reject
14965            * @kind function
14966            *
14967            * @description
14968            * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
14969            * used to forward rejection in a chain of promises. If you are dealing with the last promise in
14970            * a promise chain, you don't need to worry about it.
14971            *
14972            * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
14973            * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
14974            * a promise error callback and you want to forward the error to the promise derived from the
14975            * current promise, you have to "rethrow" the error by returning a rejection constructed via
14976            * `reject`.
14977            *
14978            * ```js
14979            *   promiseB = promiseA.then(function(result) {
14980            *     // success: do something and resolve promiseB
14981            *     //          with the old or a new result
14982            *     return result;
14983            *   }, function(reason) {
14984            *     // error: handle the error if possible and
14985            *     //        resolve promiseB with newPromiseOrValue,
14986            *     //        otherwise forward the rejection to promiseB
14987            *     if (canHandle(reason)) {
14988            *      // handle the error and recover
14989            *      return newPromiseOrValue;
14990            *     }
14991            *     return $q.reject(reason);
14992            *   });
14993            * ```
14994            *
14995            * @param {*} reason Constant, message, exception or an object representing the rejection reason.
14996            * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
14997            */
14998           var reject = function(reason) {
14999             var result = new Deferred();
15000             result.reject(reason);
15001             return result.promise;
15002           };
15003
15004           var makePromise = function makePromise(value, resolved) {
15005             var result = new Deferred();
15006             if (resolved) {
15007               result.resolve(value);
15008             } else {
15009               result.reject(value);
15010             }
15011             return result.promise;
15012           };
15013
15014           var handleCallback = function handleCallback(value, isResolved, callback) {
15015             var callbackOutput = null;
15016             try {
15017               if (isFunction(callback)) callbackOutput = callback();
15018             } catch (e) {
15019               return makePromise(e, false);
15020             }
15021             if (isPromiseLike(callbackOutput)) {
15022               return callbackOutput.then(function() {
15023                 return makePromise(value, isResolved);
15024               }, function(error) {
15025                 return makePromise(error, false);
15026               });
15027             } else {
15028               return makePromise(value, isResolved);
15029             }
15030           };
15031
15032           /**
15033            * @ngdoc method
15034            * @name $q#when
15035            * @kind function
15036            *
15037            * @description
15038            * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
15039            * This is useful when you are dealing with an object that might or might not be a promise, or if
15040            * the promise comes from a source that can't be trusted.
15041            *
15042            * @param {*} value Value or a promise
15043            * @param {Function=} successCallback
15044            * @param {Function=} errorCallback
15045            * @param {Function=} progressCallback
15046            * @returns {Promise} Returns a promise of the passed value or promise
15047            */
15048
15049
15050           var when = function(value, callback, errback, progressBack) {
15051             var result = new Deferred();
15052             result.resolve(value);
15053             return result.promise.then(callback, errback, progressBack);
15054           };
15055
15056           /**
15057            * @ngdoc method
15058            * @name $q#resolve
15059            * @kind function
15060            *
15061            * @description
15062            * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
15063            *
15064            * @param {*} value Value or a promise
15065            * @param {Function=} successCallback
15066            * @param {Function=} errorCallback
15067            * @param {Function=} progressCallback
15068            * @returns {Promise} Returns a promise of the passed value or promise
15069            */
15070           var resolve = when;
15071
15072           /**
15073            * @ngdoc method
15074            * @name $q#all
15075            * @kind function
15076            *
15077            * @description
15078            * Combines multiple promises into a single promise that is resolved when all of the input
15079            * promises are resolved.
15080            *
15081            * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
15082            * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
15083            *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
15084            *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
15085            *   with the same rejection value.
15086            */
15087
15088           function all(promises) {
15089             var deferred = new Deferred(),
15090                 counter = 0,
15091                 results = isArray(promises) ? [] : {};
15092
15093             forEach(promises, function(promise, key) {
15094               counter++;
15095               when(promise).then(function(value) {
15096                 if (results.hasOwnProperty(key)) return;
15097                 results[key] = value;
15098                 if (!(--counter)) deferred.resolve(results);
15099               }, function(reason) {
15100                 if (results.hasOwnProperty(key)) return;
15101                 deferred.reject(reason);
15102               });
15103             });
15104
15105             if (counter === 0) {
15106               deferred.resolve(results);
15107             }
15108
15109             return deferred.promise;
15110           }
15111
15112           var $Q = function Q(resolver) {
15113             if (!isFunction(resolver)) {
15114               throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
15115             }
15116
15117             if (!(this instanceof Q)) {
15118               // More useful when $Q is the Promise itself.
15119               return new Q(resolver);
15120             }
15121
15122             var deferred = new Deferred();
15123
15124             function resolveFn(value) {
15125               deferred.resolve(value);
15126             }
15127
15128             function rejectFn(reason) {
15129               deferred.reject(reason);
15130             }
15131
15132             resolver(resolveFn, rejectFn);
15133
15134             return deferred.promise;
15135           };
15136
15137           $Q.defer = defer;
15138           $Q.reject = reject;
15139           $Q.when = when;
15140           $Q.resolve = resolve;
15141           $Q.all = all;
15142
15143           return $Q;
15144         }
15145
15146         function $$RAFProvider() { //rAF
15147           this.$get = ['$window', '$timeout', function($window, $timeout) {
15148             var requestAnimationFrame = $window.requestAnimationFrame ||
15149                                         $window.webkitRequestAnimationFrame;
15150
15151             var cancelAnimationFrame = $window.cancelAnimationFrame ||
15152                                        $window.webkitCancelAnimationFrame ||
15153                                        $window.webkitCancelRequestAnimationFrame;
15154
15155             var rafSupported = !!requestAnimationFrame;
15156             var raf = rafSupported
15157               ? function(fn) {
15158                   var id = requestAnimationFrame(fn);
15159                   return function() {
15160                     cancelAnimationFrame(id);
15161                   };
15162                 }
15163               : function(fn) {
15164                   var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
15165                   return function() {
15166                     $timeout.cancel(timer);
15167                   };
15168                 };
15169
15170             raf.supported = rafSupported;
15171
15172             return raf;
15173           }];
15174         }
15175
15176         /**
15177          * DESIGN NOTES
15178          *
15179          * The design decisions behind the scope are heavily favored for speed and memory consumption.
15180          *
15181          * The typical use of scope is to watch the expressions, which most of the time return the same
15182          * value as last time so we optimize the operation.
15183          *
15184          * Closures construction is expensive in terms of speed as well as memory:
15185          *   - No closures, instead use prototypical inheritance for API
15186          *   - Internal state needs to be stored on scope directly, which means that private state is
15187          *     exposed as $$____ properties
15188          *
15189          * Loop operations are optimized by using while(count--) { ... }
15190          *   - This means that in order to keep the same order of execution as addition we have to add
15191          *     items to the array at the beginning (unshift) instead of at the end (push)
15192          *
15193          * Child scopes are created and removed often
15194          *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
15195          *
15196          * There are fewer watches than observers. This is why you don't want the observer to be implemented
15197          * in the same way as watch. Watch requires return of the initialization function which is expensive
15198          * to construct.
15199          */
15200
15201
15202         /**
15203          * @ngdoc provider
15204          * @name $rootScopeProvider
15205          * @description
15206          *
15207          * Provider for the $rootScope service.
15208          */
15209
15210         /**
15211          * @ngdoc method
15212          * @name $rootScopeProvider#digestTtl
15213          * @description
15214          *
15215          * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
15216          * assuming that the model is unstable.
15217          *
15218          * The current default is 10 iterations.
15219          *
15220          * In complex applications it's possible that the dependencies between `$watch`s will result in
15221          * several digest iterations. However if an application needs more than the default 10 digest
15222          * iterations for its model to stabilize then you should investigate what is causing the model to
15223          * continuously change during the digest.
15224          *
15225          * Increasing the TTL could have performance implications, so you should not change it without
15226          * proper justification.
15227          *
15228          * @param {number} limit The number of digest iterations.
15229          */
15230
15231
15232         /**
15233          * @ngdoc service
15234          * @name $rootScope
15235          * @description
15236          *
15237          * Every application has a single root {@link ng.$rootScope.Scope scope}.
15238          * All other scopes are descendant scopes of the root scope. Scopes provide separation
15239          * between the model and the view, via a mechanism for watching the model for changes.
15240          * They also provide event emission/broadcast and subscription facility. See the
15241          * {@link guide/scope developer guide on scopes}.
15242          */
15243         function $RootScopeProvider() {
15244           var TTL = 10;
15245           var $rootScopeMinErr = minErr('$rootScope');
15246           var lastDirtyWatch = null;
15247           var applyAsyncId = null;
15248
15249           this.digestTtl = function(value) {
15250             if (arguments.length) {
15251               TTL = value;
15252             }
15253             return TTL;
15254           };
15255
15256           function createChildScopeClass(parent) {
15257             function ChildScope() {
15258               this.$$watchers = this.$$nextSibling =
15259                   this.$$childHead = this.$$childTail = null;
15260               this.$$listeners = {};
15261               this.$$listenerCount = {};
15262               this.$$watchersCount = 0;
15263               this.$id = nextUid();
15264               this.$$ChildScope = null;
15265             }
15266             ChildScope.prototype = parent;
15267             return ChildScope;
15268           }
15269
15270           this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
15271               function($injector, $exceptionHandler, $parse, $browser) {
15272
15273             function destroyChildScope($event) {
15274                 $event.currentScope.$$destroyed = true;
15275             }
15276
15277             function cleanUpScope($scope) {
15278
15279               if (msie === 9) {
15280                 // There is a memory leak in IE9 if all child scopes are not disconnected
15281                 // completely when a scope is destroyed. So this code will recurse up through
15282                 // all this scopes children
15283                 //
15284                 // See issue https://github.com/angular/angular.js/issues/10706
15285                 $scope.$$childHead && cleanUpScope($scope.$$childHead);
15286                 $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
15287               }
15288
15289               // The code below works around IE9 and V8's memory leaks
15290               //
15291               // See:
15292               // - https://code.google.com/p/v8/issues/detail?id=2073#c26
15293               // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
15294               // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
15295
15296               $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
15297                   $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
15298             }
15299
15300             /**
15301              * @ngdoc type
15302              * @name $rootScope.Scope
15303              *
15304              * @description
15305              * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
15306              * {@link auto.$injector $injector}. Child scopes are created using the
15307              * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
15308              * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
15309              * an in-depth introduction and usage examples.
15310              *
15311              *
15312              * # Inheritance
15313              * A scope can inherit from a parent scope, as in this example:
15314              * ```js
15315                  var parent = $rootScope;
15316                  var child = parent.$new();
15317
15318                  parent.salutation = "Hello";
15319                  expect(child.salutation).toEqual('Hello');
15320
15321                  child.salutation = "Welcome";
15322                  expect(child.salutation).toEqual('Welcome');
15323                  expect(parent.salutation).toEqual('Hello');
15324              * ```
15325              *
15326              * When interacting with `Scope` in tests, additional helper methods are available on the
15327              * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
15328              * details.
15329              *
15330              *
15331              * @param {Object.<string, function()>=} providers Map of service factory which need to be
15332              *                                       provided for the current scope. Defaults to {@link ng}.
15333              * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
15334              *                              append/override services provided by `providers`. This is handy
15335              *                              when unit-testing and having the need to override a default
15336              *                              service.
15337              * @returns {Object} Newly created scope.
15338              *
15339              */
15340             function Scope() {
15341               this.$id = nextUid();
15342               this.$$phase = this.$parent = this.$$watchers =
15343                              this.$$nextSibling = this.$$prevSibling =
15344                              this.$$childHead = this.$$childTail = null;
15345               this.$root = this;
15346               this.$$destroyed = false;
15347               this.$$listeners = {};
15348               this.$$listenerCount = {};
15349               this.$$watchersCount = 0;
15350               this.$$isolateBindings = null;
15351             }
15352
15353             /**
15354              * @ngdoc property
15355              * @name $rootScope.Scope#$id
15356              *
15357              * @description
15358              * Unique scope ID (monotonically increasing) useful for debugging.
15359              */
15360
15361              /**
15362               * @ngdoc property
15363               * @name $rootScope.Scope#$parent
15364               *
15365               * @description
15366               * Reference to the parent scope.
15367               */
15368
15369               /**
15370                * @ngdoc property
15371                * @name $rootScope.Scope#$root
15372                *
15373                * @description
15374                * Reference to the root scope.
15375                */
15376
15377             Scope.prototype = {
15378               constructor: Scope,
15379               /**
15380                * @ngdoc method
15381                * @name $rootScope.Scope#$new
15382                * @kind function
15383                *
15384                * @description
15385                * Creates a new child {@link ng.$rootScope.Scope scope}.
15386                *
15387                * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
15388                * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
15389                *
15390                * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
15391                * desired for the scope and its child scopes to be permanently detached from the parent and
15392                * thus stop participating in model change detection and listener notification by invoking.
15393                *
15394                * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
15395                *         parent scope. The scope is isolated, as it can not see parent scope properties.
15396                *         When creating widgets, it is useful for the widget to not accidentally read parent
15397                *         state.
15398                *
15399                * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
15400                *                              of the newly created scope. Defaults to `this` scope if not provided.
15401                *                              This is used when creating a transclude scope to correctly place it
15402                *                              in the scope hierarchy while maintaining the correct prototypical
15403                *                              inheritance.
15404                *
15405                * @returns {Object} The newly created child scope.
15406                *
15407                */
15408               $new: function(isolate, parent) {
15409                 var child;
15410
15411                 parent = parent || this;
15412
15413                 if (isolate) {
15414                   child = new Scope();
15415                   child.$root = this.$root;
15416                 } else {
15417                   // Only create a child scope class if somebody asks for one,
15418                   // but cache it to allow the VM to optimize lookups.
15419                   if (!this.$$ChildScope) {
15420                     this.$$ChildScope = createChildScopeClass(this);
15421                   }
15422                   child = new this.$$ChildScope();
15423                 }
15424                 child.$parent = parent;
15425                 child.$$prevSibling = parent.$$childTail;
15426                 if (parent.$$childHead) {
15427                   parent.$$childTail.$$nextSibling = child;
15428                   parent.$$childTail = child;
15429                 } else {
15430                   parent.$$childHead = parent.$$childTail = child;
15431                 }
15432
15433                 // When the new scope is not isolated or we inherit from `this`, and
15434                 // the parent scope is destroyed, the property `$$destroyed` is inherited
15435                 // prototypically. In all other cases, this property needs to be set
15436                 // when the parent scope is destroyed.
15437                 // The listener needs to be added after the parent is set
15438                 if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
15439
15440                 return child;
15441               },
15442
15443               /**
15444                * @ngdoc method
15445                * @name $rootScope.Scope#$watch
15446                * @kind function
15447                *
15448                * @description
15449                * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
15450                *
15451                * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
15452                *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
15453                *   its value when executed multiple times with the same input because it may be executed multiple
15454                *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
15455                *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).
15456                * - The `listener` is called only when the value from the current `watchExpression` and the
15457                *   previous call to `watchExpression` are not equal (with the exception of the initial run,
15458                *   see below). Inequality is determined according to reference inequality,
15459                *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
15460                *    via the `!==` Javascript operator, unless `objectEquality == true`
15461                *   (see next point)
15462                * - When `objectEquality == true`, inequality of the `watchExpression` is determined
15463                *   according to the {@link angular.equals} function. To save the value of the object for
15464                *   later comparison, the {@link angular.copy} function is used. This therefore means that
15465                *   watching complex objects will have adverse memory and performance implications.
15466                * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
15467                *   This is achieved by rerunning the watchers until no changes are detected. The rerun
15468                *   iteration limit is 10 to prevent an infinite loop deadlock.
15469                *
15470                *
15471                * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
15472                * you can register a `watchExpression` function with no `listener`. (Be prepared for
15473                * multiple calls to your `watchExpression` because it will execute multiple times in a
15474                * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
15475                *
15476                * After a watcher is registered with the scope, the `listener` fn is called asynchronously
15477                * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
15478                * watcher. In rare cases, this is undesirable because the listener is called when the result
15479                * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
15480                * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
15481                * listener was called due to initialization.
15482                *
15483                *
15484                *
15485                * # Example
15486                * ```js
15487                    // let's assume that scope was dependency injected as the $rootScope
15488                    var scope = $rootScope;
15489                    scope.name = 'misko';
15490                    scope.counter = 0;
15491
15492                    expect(scope.counter).toEqual(0);
15493                    scope.$watch('name', function(newValue, oldValue) {
15494                      scope.counter = scope.counter + 1;
15495                    });
15496                    expect(scope.counter).toEqual(0);
15497
15498                    scope.$digest();
15499                    // the listener is always called during the first $digest loop after it was registered
15500                    expect(scope.counter).toEqual(1);
15501
15502                    scope.$digest();
15503                    // but now it will not be called unless the value changes
15504                    expect(scope.counter).toEqual(1);
15505
15506                    scope.name = 'adam';
15507                    scope.$digest();
15508                    expect(scope.counter).toEqual(2);
15509
15510
15511
15512                    // Using a function as a watchExpression
15513                    var food;
15514                    scope.foodCounter = 0;
15515                    expect(scope.foodCounter).toEqual(0);
15516                    scope.$watch(
15517                      // This function returns the value being watched. It is called for each turn of the $digest loop
15518                      function() { return food; },
15519                      // This is the change listener, called when the value returned from the above function changes
15520                      function(newValue, oldValue) {
15521                        if ( newValue !== oldValue ) {
15522                          // Only increment the counter if the value changed
15523                          scope.foodCounter = scope.foodCounter + 1;
15524                        }
15525                      }
15526                    );
15527                    // No digest has been run so the counter will be zero
15528                    expect(scope.foodCounter).toEqual(0);
15529
15530                    // Run the digest but since food has not changed count will still be zero
15531                    scope.$digest();
15532                    expect(scope.foodCounter).toEqual(0);
15533
15534                    // Update food and run digest.  Now the counter will increment
15535                    food = 'cheeseburger';
15536                    scope.$digest();
15537                    expect(scope.foodCounter).toEqual(1);
15538
15539                * ```
15540                *
15541                *
15542                *
15543                * @param {(function()|string)} watchExpression Expression that is evaluated on each
15544                *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
15545                *    a call to the `listener`.
15546                *
15547                *    - `string`: Evaluated as {@link guide/expression expression}
15548                *    - `function(scope)`: called with current `scope` as a parameter.
15549                * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
15550                *    of `watchExpression` changes.
15551                *
15552                *    - `newVal` contains the current value of the `watchExpression`
15553                *    - `oldVal` contains the previous value of the `watchExpression`
15554                *    - `scope` refers to the current scope
15555                * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
15556                *     comparing for reference equality.
15557                * @returns {function()} Returns a deregistration function for this listener.
15558                */
15559               $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
15560                 var get = $parse(watchExp);
15561
15562                 if (get.$$watchDelegate) {
15563                   return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
15564                 }
15565                 var scope = this,
15566                     array = scope.$$watchers,
15567                     watcher = {
15568                       fn: listener,
15569                       last: initWatchVal,
15570                       get: get,
15571                       exp: prettyPrintExpression || watchExp,
15572                       eq: !!objectEquality
15573                     };
15574
15575                 lastDirtyWatch = null;
15576
15577                 if (!isFunction(listener)) {
15578                   watcher.fn = noop;
15579                 }
15580
15581                 if (!array) {
15582                   array = scope.$$watchers = [];
15583                 }
15584                 // we use unshift since we use a while loop in $digest for speed.
15585                 // the while loop reads in reverse order.
15586                 array.unshift(watcher);
15587                 incrementWatchersCount(this, 1);
15588
15589                 return function deregisterWatch() {
15590                   if (arrayRemove(array, watcher) >= 0) {
15591                     incrementWatchersCount(scope, -1);
15592                   }
15593                   lastDirtyWatch = null;
15594                 };
15595               },
15596
15597               /**
15598                * @ngdoc method
15599                * @name $rootScope.Scope#$watchGroup
15600                * @kind function
15601                *
15602                * @description
15603                * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
15604                * If any one expression in the collection changes the `listener` is executed.
15605                *
15606                * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
15607                *   call to $digest() to see if any items changes.
15608                * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
15609                *
15610                * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
15611                * watched using {@link ng.$rootScope.Scope#$watch $watch()}
15612                *
15613                * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
15614                *    expression in `watchExpressions` changes
15615                *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
15616                *    those of `watchExpression`
15617                *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
15618                *    those of `watchExpression`
15619                *    The `scope` refers to the current scope.
15620                * @returns {function()} Returns a de-registration function for all listeners.
15621                */
15622               $watchGroup: function(watchExpressions, listener) {
15623                 var oldValues = new Array(watchExpressions.length);
15624                 var newValues = new Array(watchExpressions.length);
15625                 var deregisterFns = [];
15626                 var self = this;
15627                 var changeReactionScheduled = false;
15628                 var firstRun = true;
15629
15630                 if (!watchExpressions.length) {
15631                   // No expressions means we call the listener ASAP
15632                   var shouldCall = true;
15633                   self.$evalAsync(function() {
15634                     if (shouldCall) listener(newValues, newValues, self);
15635                   });
15636                   return function deregisterWatchGroup() {
15637                     shouldCall = false;
15638                   };
15639                 }
15640
15641                 if (watchExpressions.length === 1) {
15642                   // Special case size of one
15643                   return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
15644                     newValues[0] = value;
15645                     oldValues[0] = oldValue;
15646                     listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
15647                   });
15648                 }
15649
15650                 forEach(watchExpressions, function(expr, i) {
15651                   var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
15652                     newValues[i] = value;
15653                     oldValues[i] = oldValue;
15654                     if (!changeReactionScheduled) {
15655                       changeReactionScheduled = true;
15656                       self.$evalAsync(watchGroupAction);
15657                     }
15658                   });
15659                   deregisterFns.push(unwatchFn);
15660                 });
15661
15662                 function watchGroupAction() {
15663                   changeReactionScheduled = false;
15664
15665                   if (firstRun) {
15666                     firstRun = false;
15667                     listener(newValues, newValues, self);
15668                   } else {
15669                     listener(newValues, oldValues, self);
15670                   }
15671                 }
15672
15673                 return function deregisterWatchGroup() {
15674                   while (deregisterFns.length) {
15675                     deregisterFns.shift()();
15676                   }
15677                 };
15678               },
15679
15680
15681               /**
15682                * @ngdoc method
15683                * @name $rootScope.Scope#$watchCollection
15684                * @kind function
15685                *
15686                * @description
15687                * Shallow watches the properties of an object and fires whenever any of the properties change
15688                * (for arrays, this implies watching the array items; for object maps, this implies watching
15689                * the properties). If a change is detected, the `listener` callback is fired.
15690                *
15691                * - The `obj` collection is observed via standard $watch operation and is examined on every
15692                *   call to $digest() to see if any items have been added, removed, or moved.
15693                * - The `listener` is called whenever anything within the `obj` has changed. Examples include
15694                *   adding, removing, and moving items belonging to an object or array.
15695                *
15696                *
15697                * # Example
15698                * ```js
15699                   $scope.names = ['igor', 'matias', 'misko', 'james'];
15700                   $scope.dataCount = 4;
15701
15702                   $scope.$watchCollection('names', function(newNames, oldNames) {
15703                     $scope.dataCount = newNames.length;
15704                   });
15705
15706                   expect($scope.dataCount).toEqual(4);
15707                   $scope.$digest();
15708
15709                   //still at 4 ... no changes
15710                   expect($scope.dataCount).toEqual(4);
15711
15712                   $scope.names.pop();
15713                   $scope.$digest();
15714
15715                   //now there's been a change
15716                   expect($scope.dataCount).toEqual(3);
15717                * ```
15718                *
15719                *
15720                * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
15721                *    expression value should evaluate to an object or an array which is observed on each
15722                *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
15723                *    collection will trigger a call to the `listener`.
15724                *
15725                * @param {function(newCollection, oldCollection, scope)} listener a callback function called
15726                *    when a change is detected.
15727                *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
15728                *    - The `oldCollection` object is a copy of the former collection data.
15729                *      Due to performance considerations, the`oldCollection` value is computed only if the
15730                *      `listener` function declares two or more arguments.
15731                *    - The `scope` argument refers to the current scope.
15732                *
15733                * @returns {function()} Returns a de-registration function for this listener. When the
15734                *    de-registration function is executed, the internal watch operation is terminated.
15735                */
15736               $watchCollection: function(obj, listener) {
15737                 $watchCollectionInterceptor.$stateful = true;
15738
15739                 var self = this;
15740                 // the current value, updated on each dirty-check run
15741                 var newValue;
15742                 // a shallow copy of the newValue from the last dirty-check run,
15743                 // updated to match newValue during dirty-check run
15744                 var oldValue;
15745                 // a shallow copy of the newValue from when the last change happened
15746                 var veryOldValue;
15747                 // only track veryOldValue if the listener is asking for it
15748                 var trackVeryOldValue = (listener.length > 1);
15749                 var changeDetected = 0;
15750                 var changeDetector = $parse(obj, $watchCollectionInterceptor);
15751                 var internalArray = [];
15752                 var internalObject = {};
15753                 var initRun = true;
15754                 var oldLength = 0;
15755
15756                 function $watchCollectionInterceptor(_value) {
15757                   newValue = _value;
15758                   var newLength, key, bothNaN, newItem, oldItem;
15759
15760                   // If the new value is undefined, then return undefined as the watch may be a one-time watch
15761                   if (isUndefined(newValue)) return;
15762
15763                   if (!isObject(newValue)) { // if primitive
15764                     if (oldValue !== newValue) {
15765                       oldValue = newValue;
15766                       changeDetected++;
15767                     }
15768                   } else if (isArrayLike(newValue)) {
15769                     if (oldValue !== internalArray) {
15770                       // we are transitioning from something which was not an array into array.
15771                       oldValue = internalArray;
15772                       oldLength = oldValue.length = 0;
15773                       changeDetected++;
15774                     }
15775
15776                     newLength = newValue.length;
15777
15778                     if (oldLength !== newLength) {
15779                       // if lengths do not match we need to trigger change notification
15780                       changeDetected++;
15781                       oldValue.length = oldLength = newLength;
15782                     }
15783                     // copy the items to oldValue and look for changes.
15784                     for (var i = 0; i < newLength; i++) {
15785                       oldItem = oldValue[i];
15786                       newItem = newValue[i];
15787
15788                       bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15789                       if (!bothNaN && (oldItem !== newItem)) {
15790                         changeDetected++;
15791                         oldValue[i] = newItem;
15792                       }
15793                     }
15794                   } else {
15795                     if (oldValue !== internalObject) {
15796                       // we are transitioning from something which was not an object into object.
15797                       oldValue = internalObject = {};
15798                       oldLength = 0;
15799                       changeDetected++;
15800                     }
15801                     // copy the items to oldValue and look for changes.
15802                     newLength = 0;
15803                     for (key in newValue) {
15804                       if (hasOwnProperty.call(newValue, key)) {
15805                         newLength++;
15806                         newItem = newValue[key];
15807                         oldItem = oldValue[key];
15808
15809                         if (key in oldValue) {
15810                           bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15811                           if (!bothNaN && (oldItem !== newItem)) {
15812                             changeDetected++;
15813                             oldValue[key] = newItem;
15814                           }
15815                         } else {
15816                           oldLength++;
15817                           oldValue[key] = newItem;
15818                           changeDetected++;
15819                         }
15820                       }
15821                     }
15822                     if (oldLength > newLength) {
15823                       // we used to have more keys, need to find them and destroy them.
15824                       changeDetected++;
15825                       for (key in oldValue) {
15826                         if (!hasOwnProperty.call(newValue, key)) {
15827                           oldLength--;
15828                           delete oldValue[key];
15829                         }
15830                       }
15831                     }
15832                   }
15833                   return changeDetected;
15834                 }
15835
15836                 function $watchCollectionAction() {
15837                   if (initRun) {
15838                     initRun = false;
15839                     listener(newValue, newValue, self);
15840                   } else {
15841                     listener(newValue, veryOldValue, self);
15842                   }
15843
15844                   // make a copy for the next time a collection is changed
15845                   if (trackVeryOldValue) {
15846                     if (!isObject(newValue)) {
15847                       //primitive
15848                       veryOldValue = newValue;
15849                     } else if (isArrayLike(newValue)) {
15850                       veryOldValue = new Array(newValue.length);
15851                       for (var i = 0; i < newValue.length; i++) {
15852                         veryOldValue[i] = newValue[i];
15853                       }
15854                     } else { // if object
15855                       veryOldValue = {};
15856                       for (var key in newValue) {
15857                         if (hasOwnProperty.call(newValue, key)) {
15858                           veryOldValue[key] = newValue[key];
15859                         }
15860                       }
15861                     }
15862                   }
15863                 }
15864
15865                 return this.$watch(changeDetector, $watchCollectionAction);
15866               },
15867
15868               /**
15869                * @ngdoc method
15870                * @name $rootScope.Scope#$digest
15871                * @kind function
15872                *
15873                * @description
15874                * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
15875                * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
15876                * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
15877                * until no more listeners are firing. This means that it is possible to get into an infinite
15878                * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
15879                * iterations exceeds 10.
15880                *
15881                * Usually, you don't call `$digest()` directly in
15882                * {@link ng.directive:ngController controllers} or in
15883                * {@link ng.$compileProvider#directive directives}.
15884                * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
15885                * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
15886                *
15887                * If you want to be notified whenever `$digest()` is called,
15888                * you can register a `watchExpression` function with
15889                * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
15890                *
15891                * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
15892                *
15893                * # Example
15894                * ```js
15895                    var scope = ...;
15896                    scope.name = 'misko';
15897                    scope.counter = 0;
15898
15899                    expect(scope.counter).toEqual(0);
15900                    scope.$watch('name', function(newValue, oldValue) {
15901                      scope.counter = scope.counter + 1;
15902                    });
15903                    expect(scope.counter).toEqual(0);
15904
15905                    scope.$digest();
15906                    // the listener is always called during the first $digest loop after it was registered
15907                    expect(scope.counter).toEqual(1);
15908
15909                    scope.$digest();
15910                    // but now it will not be called unless the value changes
15911                    expect(scope.counter).toEqual(1);
15912
15913                    scope.name = 'adam';
15914                    scope.$digest();
15915                    expect(scope.counter).toEqual(2);
15916                * ```
15917                *
15918                */
15919               $digest: function() {
15920                 var watch, value, last,
15921                     watchers,
15922                     length,
15923                     dirty, ttl = TTL,
15924                     next, current, target = this,
15925                     watchLog = [],
15926                     logIdx, logMsg, asyncTask;
15927
15928                 beginPhase('$digest');
15929                 // Check for changes to browser url that happened in sync before the call to $digest
15930                 $browser.$$checkUrlChange();
15931
15932                 if (this === $rootScope && applyAsyncId !== null) {
15933                   // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
15934                   // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
15935                   $browser.defer.cancel(applyAsyncId);
15936                   flushApplyAsync();
15937                 }
15938
15939                 lastDirtyWatch = null;
15940
15941                 do { // "while dirty" loop
15942                   dirty = false;
15943                   current = target;
15944
15945                   while (asyncQueue.length) {
15946                     try {
15947                       asyncTask = asyncQueue.shift();
15948                       asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
15949                     } catch (e) {
15950                       $exceptionHandler(e);
15951                     }
15952                     lastDirtyWatch = null;
15953                   }
15954
15955                   traverseScopesLoop:
15956                   do { // "traverse the scopes" loop
15957                     if ((watchers = current.$$watchers)) {
15958                       // process our watches
15959                       length = watchers.length;
15960                       while (length--) {
15961                         try {
15962                           watch = watchers[length];
15963                           // Most common watches are on primitives, in which case we can short
15964                           // circuit it with === operator, only when === fails do we use .equals
15965                           if (watch) {
15966                             if ((value = watch.get(current)) !== (last = watch.last) &&
15967                                 !(watch.eq
15968                                     ? equals(value, last)
15969                                     : (typeof value === 'number' && typeof last === 'number'
15970                                        && isNaN(value) && isNaN(last)))) {
15971                               dirty = true;
15972                               lastDirtyWatch = watch;
15973                               watch.last = watch.eq ? copy(value, null) : value;
15974                               watch.fn(value, ((last === initWatchVal) ? value : last), current);
15975                               if (ttl < 5) {
15976                                 logIdx = 4 - ttl;
15977                                 if (!watchLog[logIdx]) watchLog[logIdx] = [];
15978                                 watchLog[logIdx].push({
15979                                   msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
15980                                   newVal: value,
15981                                   oldVal: last
15982                                 });
15983                               }
15984                             } else if (watch === lastDirtyWatch) {
15985                               // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
15986                               // have already been tested.
15987                               dirty = false;
15988                               break traverseScopesLoop;
15989                             }
15990                           }
15991                         } catch (e) {
15992                           $exceptionHandler(e);
15993                         }
15994                       }
15995                     }
15996
15997                     // Insanity Warning: scope depth-first traversal
15998                     // yes, this code is a bit crazy, but it works and we have tests to prove it!
15999                     // this piece should be kept in sync with the traversal in $broadcast
16000                     if (!(next = ((current.$$watchersCount && current.$$childHead) ||
16001                         (current !== target && current.$$nextSibling)))) {
16002                       while (current !== target && !(next = current.$$nextSibling)) {
16003                         current = current.$parent;
16004                       }
16005                     }
16006                   } while ((current = next));
16007
16008                   // `break traverseScopesLoop;` takes us to here
16009
16010                   if ((dirty || asyncQueue.length) && !(ttl--)) {
16011                     clearPhase();
16012                     throw $rootScopeMinErr('infdig',
16013                         '{0} $digest() iterations reached. Aborting!\n' +
16014                         'Watchers fired in the last 5 iterations: {1}',
16015                         TTL, watchLog);
16016                   }
16017
16018                 } while (dirty || asyncQueue.length);
16019
16020                 clearPhase();
16021
16022                 while (postDigestQueue.length) {
16023                   try {
16024                     postDigestQueue.shift()();
16025                   } catch (e) {
16026                     $exceptionHandler(e);
16027                   }
16028                 }
16029               },
16030
16031
16032               /**
16033                * @ngdoc event
16034                * @name $rootScope.Scope#$destroy
16035                * @eventType broadcast on scope being destroyed
16036                *
16037                * @description
16038                * Broadcasted when a scope and its children are being destroyed.
16039                *
16040                * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
16041                * clean up DOM bindings before an element is removed from the DOM.
16042                */
16043
16044               /**
16045                * @ngdoc method
16046                * @name $rootScope.Scope#$destroy
16047                * @kind function
16048                *
16049                * @description
16050                * Removes the current scope (and all of its children) from the parent scope. Removal implies
16051                * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
16052                * propagate to the current scope and its children. Removal also implies that the current
16053                * scope is eligible for garbage collection.
16054                *
16055                * The `$destroy()` is usually used by directives such as
16056                * {@link ng.directive:ngRepeat ngRepeat} for managing the
16057                * unrolling of the loop.
16058                *
16059                * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
16060                * Application code can register a `$destroy` event handler that will give it a chance to
16061                * perform any necessary cleanup.
16062                *
16063                * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
16064                * clean up DOM bindings before an element is removed from the DOM.
16065                */
16066               $destroy: function() {
16067                 // We can't destroy a scope that has been already destroyed.
16068                 if (this.$$destroyed) return;
16069                 var parent = this.$parent;
16070
16071                 this.$broadcast('$destroy');
16072                 this.$$destroyed = true;
16073
16074                 if (this === $rootScope) {
16075                   //Remove handlers attached to window when $rootScope is removed
16076                   $browser.$$applicationDestroyed();
16077                 }
16078
16079                 incrementWatchersCount(this, -this.$$watchersCount);
16080                 for (var eventName in this.$$listenerCount) {
16081                   decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
16082                 }
16083
16084                 // sever all the references to parent scopes (after this cleanup, the current scope should
16085                 // not be retained by any of our references and should be eligible for garbage collection)
16086                 if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
16087                 if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
16088                 if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
16089                 if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
16090
16091                 // Disable listeners, watchers and apply/digest methods
16092                 this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
16093                 this.$on = this.$watch = this.$watchGroup = function() { return noop; };
16094                 this.$$listeners = {};
16095
16096                 // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
16097                 this.$$nextSibling = null;
16098                 cleanUpScope(this);
16099               },
16100
16101               /**
16102                * @ngdoc method
16103                * @name $rootScope.Scope#$eval
16104                * @kind function
16105                *
16106                * @description
16107                * Executes the `expression` on the current scope and returns the result. Any exceptions in
16108                * the expression are propagated (uncaught). This is useful when evaluating Angular
16109                * expressions.
16110                *
16111                * # Example
16112                * ```js
16113                    var scope = ng.$rootScope.Scope();
16114                    scope.a = 1;
16115                    scope.b = 2;
16116
16117                    expect(scope.$eval('a+b')).toEqual(3);
16118                    expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
16119                * ```
16120                *
16121                * @param {(string|function())=} expression An angular expression to be executed.
16122                *
16123                *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
16124                *    - `function(scope)`: execute the function with the current `scope` parameter.
16125                *
16126                * @param {(object)=} locals Local variables object, useful for overriding values in scope.
16127                * @returns {*} The result of evaluating the expression.
16128                */
16129               $eval: function(expr, locals) {
16130                 return $parse(expr)(this, locals);
16131               },
16132
16133               /**
16134                * @ngdoc method
16135                * @name $rootScope.Scope#$evalAsync
16136                * @kind function
16137                *
16138                * @description
16139                * Executes the expression on the current scope at a later point in time.
16140                *
16141                * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
16142                * that:
16143                *
16144                *   - it will execute after the function that scheduled the evaluation (preferably before DOM
16145                *     rendering).
16146                *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
16147                *     `expression` execution.
16148                *
16149                * Any exceptions from the execution of the expression are forwarded to the
16150                * {@link ng.$exceptionHandler $exceptionHandler} service.
16151                *
16152                * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
16153                * will be scheduled. However, it is encouraged to always call code that changes the model
16154                * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
16155                *
16156                * @param {(string|function())=} expression An angular expression to be executed.
16157                *
16158                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16159                *    - `function(scope)`: execute the function with the current `scope` parameter.
16160                *
16161                * @param {(object)=} locals Local variables object, useful for overriding values in scope.
16162                */
16163               $evalAsync: function(expr, locals) {
16164                 // if we are outside of an $digest loop and this is the first time we are scheduling async
16165                 // task also schedule async auto-flush
16166                 if (!$rootScope.$$phase && !asyncQueue.length) {
16167                   $browser.defer(function() {
16168                     if (asyncQueue.length) {
16169                       $rootScope.$digest();
16170                     }
16171                   });
16172                 }
16173
16174                 asyncQueue.push({scope: this, expression: expr, locals: locals});
16175               },
16176
16177               $$postDigest: function(fn) {
16178                 postDigestQueue.push(fn);
16179               },
16180
16181               /**
16182                * @ngdoc method
16183                * @name $rootScope.Scope#$apply
16184                * @kind function
16185                *
16186                * @description
16187                * `$apply()` is used to execute an expression in angular from outside of the angular
16188                * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
16189                * Because we are calling into the angular framework we need to perform proper scope life
16190                * cycle of {@link ng.$exceptionHandler exception handling},
16191                * {@link ng.$rootScope.Scope#$digest executing watches}.
16192                *
16193                * ## Life cycle
16194                *
16195                * # Pseudo-Code of `$apply()`
16196                * ```js
16197                    function $apply(expr) {
16198                      try {
16199                        return $eval(expr);
16200                      } catch (e) {
16201                        $exceptionHandler(e);
16202                      } finally {
16203                        $root.$digest();
16204                      }
16205                    }
16206                * ```
16207                *
16208                *
16209                * Scope's `$apply()` method transitions through the following stages:
16210                *
16211                * 1. The {@link guide/expression expression} is executed using the
16212                *    {@link ng.$rootScope.Scope#$eval $eval()} method.
16213                * 2. Any exceptions from the execution of the expression are forwarded to the
16214                *    {@link ng.$exceptionHandler $exceptionHandler} service.
16215                * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
16216                *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
16217                *
16218                *
16219                * @param {(string|function())=} exp An angular expression to be executed.
16220                *
16221                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16222                *    - `function(scope)`: execute the function with current `scope` parameter.
16223                *
16224                * @returns {*} The result of evaluating the expression.
16225                */
16226               $apply: function(expr) {
16227                 try {
16228                   beginPhase('$apply');
16229                   try {
16230                     return this.$eval(expr);
16231                   } finally {
16232                     clearPhase();
16233                   }
16234                 } catch (e) {
16235                   $exceptionHandler(e);
16236                 } finally {
16237                   try {
16238                     $rootScope.$digest();
16239                   } catch (e) {
16240                     $exceptionHandler(e);
16241                     throw e;
16242                   }
16243                 }
16244               },
16245
16246               /**
16247                * @ngdoc method
16248                * @name $rootScope.Scope#$applyAsync
16249                * @kind function
16250                *
16251                * @description
16252                * Schedule the invocation of $apply to occur at a later time. The actual time difference
16253                * varies across browsers, but is typically around ~10 milliseconds.
16254                *
16255                * This can be used to queue up multiple expressions which need to be evaluated in the same
16256                * digest.
16257                *
16258                * @param {(string|function())=} exp An angular expression to be executed.
16259                *
16260                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16261                *    - `function(scope)`: execute the function with current `scope` parameter.
16262                */
16263               $applyAsync: function(expr) {
16264                 var scope = this;
16265                 expr && applyAsyncQueue.push($applyAsyncExpression);
16266                 scheduleApplyAsync();
16267
16268                 function $applyAsyncExpression() {
16269                   scope.$eval(expr);
16270                 }
16271               },
16272
16273               /**
16274                * @ngdoc method
16275                * @name $rootScope.Scope#$on
16276                * @kind function
16277                *
16278                * @description
16279                * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
16280                * discussion of event life cycle.
16281                *
16282                * The event listener function format is: `function(event, args...)`. The `event` object
16283                * passed into the listener has the following attributes:
16284                *
16285                *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
16286                *     `$broadcast`-ed.
16287                *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
16288                *     event propagates through the scope hierarchy, this property is set to null.
16289                *   - `name` - `{string}`: name of the event.
16290                *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
16291                *     further event propagation (available only for events that were `$emit`-ed).
16292                *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
16293                *     to true.
16294                *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
16295                *
16296                * @param {string} name Event name to listen on.
16297                * @param {function(event, ...args)} listener Function to call when the event is emitted.
16298                * @returns {function()} Returns a deregistration function for this listener.
16299                */
16300               $on: function(name, listener) {
16301                 var namedListeners = this.$$listeners[name];
16302                 if (!namedListeners) {
16303                   this.$$listeners[name] = namedListeners = [];
16304                 }
16305                 namedListeners.push(listener);
16306
16307                 var current = this;
16308                 do {
16309                   if (!current.$$listenerCount[name]) {
16310                     current.$$listenerCount[name] = 0;
16311                   }
16312                   current.$$listenerCount[name]++;
16313                 } while ((current = current.$parent));
16314
16315                 var self = this;
16316                 return function() {
16317                   var indexOfListener = namedListeners.indexOf(listener);
16318                   if (indexOfListener !== -1) {
16319                     namedListeners[indexOfListener] = null;
16320                     decrementListenerCount(self, 1, name);
16321                   }
16322                 };
16323               },
16324
16325
16326               /**
16327                * @ngdoc method
16328                * @name $rootScope.Scope#$emit
16329                * @kind function
16330                *
16331                * @description
16332                * Dispatches an event `name` upwards through the scope hierarchy notifying the
16333                * registered {@link ng.$rootScope.Scope#$on} listeners.
16334                *
16335                * The event life cycle starts at the scope on which `$emit` was called. All
16336                * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
16337                * notified. Afterwards, the event traverses upwards toward the root scope and calls all
16338                * registered listeners along the way. The event will stop propagating if one of the listeners
16339                * cancels it.
16340                *
16341                * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16342                * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16343                *
16344                * @param {string} name Event name to emit.
16345                * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16346                * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
16347                */
16348               $emit: function(name, args) {
16349                 var empty = [],
16350                     namedListeners,
16351                     scope = this,
16352                     stopPropagation = false,
16353                     event = {
16354                       name: name,
16355                       targetScope: scope,
16356                       stopPropagation: function() {stopPropagation = true;},
16357                       preventDefault: function() {
16358                         event.defaultPrevented = true;
16359                       },
16360                       defaultPrevented: false
16361                     },
16362                     listenerArgs = concat([event], arguments, 1),
16363                     i, length;
16364
16365                 do {
16366                   namedListeners = scope.$$listeners[name] || empty;
16367                   event.currentScope = scope;
16368                   for (i = 0, length = namedListeners.length; i < length; i++) {
16369
16370                     // if listeners were deregistered, defragment the array
16371                     if (!namedListeners[i]) {
16372                       namedListeners.splice(i, 1);
16373                       i--;
16374                       length--;
16375                       continue;
16376                     }
16377                     try {
16378                       //allow all listeners attached to the current scope to run
16379                       namedListeners[i].apply(null, listenerArgs);
16380                     } catch (e) {
16381                       $exceptionHandler(e);
16382                     }
16383                   }
16384                   //if any listener on the current scope stops propagation, prevent bubbling
16385                   if (stopPropagation) {
16386                     event.currentScope = null;
16387                     return event;
16388                   }
16389                   //traverse upwards
16390                   scope = scope.$parent;
16391                 } while (scope);
16392
16393                 event.currentScope = null;
16394
16395                 return event;
16396               },
16397
16398
16399               /**
16400                * @ngdoc method
16401                * @name $rootScope.Scope#$broadcast
16402                * @kind function
16403                *
16404                * @description
16405                * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
16406                * registered {@link ng.$rootScope.Scope#$on} listeners.
16407                *
16408                * The event life cycle starts at the scope on which `$broadcast` was called. All
16409                * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
16410                * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
16411                * scope and calls all registered listeners along the way. The event cannot be canceled.
16412                *
16413                * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16414                * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16415                *
16416                * @param {string} name Event name to broadcast.
16417                * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16418                * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
16419                */
16420               $broadcast: function(name, args) {
16421                 var target = this,
16422                     current = target,
16423                     next = target,
16424                     event = {
16425                       name: name,
16426                       targetScope: target,
16427                       preventDefault: function() {
16428                         event.defaultPrevented = true;
16429                       },
16430                       defaultPrevented: false
16431                     };
16432
16433                 if (!target.$$listenerCount[name]) return event;
16434
16435                 var listenerArgs = concat([event], arguments, 1),
16436                     listeners, i, length;
16437
16438                 //down while you can, then up and next sibling or up and next sibling until back at root
16439                 while ((current = next)) {
16440                   event.currentScope = current;
16441                   listeners = current.$$listeners[name] || [];
16442                   for (i = 0, length = listeners.length; i < length; i++) {
16443                     // if listeners were deregistered, defragment the array
16444                     if (!listeners[i]) {
16445                       listeners.splice(i, 1);
16446                       i--;
16447                       length--;
16448                       continue;
16449                     }
16450
16451                     try {
16452                       listeners[i].apply(null, listenerArgs);
16453                     } catch (e) {
16454                       $exceptionHandler(e);
16455                     }
16456                   }
16457
16458                   // Insanity Warning: scope depth-first traversal
16459                   // yes, this code is a bit crazy, but it works and we have tests to prove it!
16460                   // this piece should be kept in sync with the traversal in $digest
16461                   // (though it differs due to having the extra check for $$listenerCount)
16462                   if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
16463                       (current !== target && current.$$nextSibling)))) {
16464                     while (current !== target && !(next = current.$$nextSibling)) {
16465                       current = current.$parent;
16466                     }
16467                   }
16468                 }
16469
16470                 event.currentScope = null;
16471                 return event;
16472               }
16473             };
16474
16475             var $rootScope = new Scope();
16476
16477             //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
16478             var asyncQueue = $rootScope.$$asyncQueue = [];
16479             var postDigestQueue = $rootScope.$$postDigestQueue = [];
16480             var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
16481
16482             return $rootScope;
16483
16484
16485             function beginPhase(phase) {
16486               if ($rootScope.$$phase) {
16487                 throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
16488               }
16489
16490               $rootScope.$$phase = phase;
16491             }
16492
16493             function clearPhase() {
16494               $rootScope.$$phase = null;
16495             }
16496
16497             function incrementWatchersCount(current, count) {
16498               do {
16499                 current.$$watchersCount += count;
16500               } while ((current = current.$parent));
16501             }
16502
16503             function decrementListenerCount(current, count, name) {
16504               do {
16505                 current.$$listenerCount[name] -= count;
16506
16507                 if (current.$$listenerCount[name] === 0) {
16508                   delete current.$$listenerCount[name];
16509                 }
16510               } while ((current = current.$parent));
16511             }
16512
16513             /**
16514              * function used as an initial value for watchers.
16515              * because it's unique we can easily tell it apart from other values
16516              */
16517             function initWatchVal() {}
16518
16519             function flushApplyAsync() {
16520               while (applyAsyncQueue.length) {
16521                 try {
16522                   applyAsyncQueue.shift()();
16523                 } catch (e) {
16524                   $exceptionHandler(e);
16525                 }
16526               }
16527               applyAsyncId = null;
16528             }
16529
16530             function scheduleApplyAsync() {
16531               if (applyAsyncId === null) {
16532                 applyAsyncId = $browser.defer(function() {
16533                   $rootScope.$apply(flushApplyAsync);
16534                 });
16535               }
16536             }
16537           }];
16538         }
16539
16540         /**
16541          * @description
16542          * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
16543          */
16544         function $$SanitizeUriProvider() {
16545           var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
16546             imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
16547
16548           /**
16549            * @description
16550            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16551            * urls during a[href] sanitization.
16552            *
16553            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16554            *
16555            * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
16556            * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
16557            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16558            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16559            *
16560            * @param {RegExp=} regexp New regexp to whitelist urls with.
16561            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16562            *    chaining otherwise.
16563            */
16564           this.aHrefSanitizationWhitelist = function(regexp) {
16565             if (isDefined(regexp)) {
16566               aHrefSanitizationWhitelist = regexp;
16567               return this;
16568             }
16569             return aHrefSanitizationWhitelist;
16570           };
16571
16572
16573           /**
16574            * @description
16575            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16576            * urls during img[src] sanitization.
16577            *
16578            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16579            *
16580            * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
16581            * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
16582            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16583            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16584            *
16585            * @param {RegExp=} regexp New regexp to whitelist urls with.
16586            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16587            *    chaining otherwise.
16588            */
16589           this.imgSrcSanitizationWhitelist = function(regexp) {
16590             if (isDefined(regexp)) {
16591               imgSrcSanitizationWhitelist = regexp;
16592               return this;
16593             }
16594             return imgSrcSanitizationWhitelist;
16595           };
16596
16597           this.$get = function() {
16598             return function sanitizeUri(uri, isImage) {
16599               var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
16600               var normalizedVal;
16601               normalizedVal = urlResolve(uri).href;
16602               if (normalizedVal !== '' && !normalizedVal.match(regex)) {
16603                 return 'unsafe:' + normalizedVal;
16604               }
16605               return uri;
16606             };
16607           };
16608         }
16609
16610         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16611          *     Any commits to this file should be reviewed with security in mind.  *
16612          *   Changes to this file can potentially create security vulnerabilities. *
16613          *          An approval from 2 Core members with history of modifying      *
16614          *                         this file is required.                          *
16615          *                                                                         *
16616          *  Does the change somehow allow for arbitrary javascript to be executed? *
16617          *    Or allows for someone to change the prototype of built-in objects?   *
16618          *     Or gives undesired access to variables likes document or window?    *
16619          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16620
16621         var $sceMinErr = minErr('$sce');
16622
16623         var SCE_CONTEXTS = {
16624           HTML: 'html',
16625           CSS: 'css',
16626           URL: 'url',
16627           // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
16628           // url.  (e.g. ng-include, script src, templateUrl)
16629           RESOURCE_URL: 'resourceUrl',
16630           JS: 'js'
16631         };
16632
16633         // Helper functions follow.
16634
16635         function adjustMatcher(matcher) {
16636           if (matcher === 'self') {
16637             return matcher;
16638           } else if (isString(matcher)) {
16639             // Strings match exactly except for 2 wildcards - '*' and '**'.
16640             // '*' matches any character except those from the set ':/.?&'.
16641             // '**' matches any character (like .* in a RegExp).
16642             // More than 2 *'s raises an error as it's ill defined.
16643             if (matcher.indexOf('***') > -1) {
16644               throw $sceMinErr('iwcard',
16645                   'Illegal sequence *** in string matcher.  String: {0}', matcher);
16646             }
16647             matcher = escapeForRegexp(matcher).
16648                           replace('\\*\\*', '.*').
16649                           replace('\\*', '[^:/.?&;]*');
16650             return new RegExp('^' + matcher + '$');
16651           } else if (isRegExp(matcher)) {
16652             // The only other type of matcher allowed is a Regexp.
16653             // Match entire URL / disallow partial matches.
16654             // Flags are reset (i.e. no global, ignoreCase or multiline)
16655             return new RegExp('^' + matcher.source + '$');
16656           } else {
16657             throw $sceMinErr('imatcher',
16658                 'Matchers may only be "self", string patterns or RegExp objects');
16659           }
16660         }
16661
16662
16663         function adjustMatchers(matchers) {
16664           var adjustedMatchers = [];
16665           if (isDefined(matchers)) {
16666             forEach(matchers, function(matcher) {
16667               adjustedMatchers.push(adjustMatcher(matcher));
16668             });
16669           }
16670           return adjustedMatchers;
16671         }
16672
16673
16674         /**
16675          * @ngdoc service
16676          * @name $sceDelegate
16677          * @kind function
16678          *
16679          * @description
16680          *
16681          * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
16682          * Contextual Escaping (SCE)} services to AngularJS.
16683          *
16684          * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
16685          * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
16686          * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
16687          * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
16688          * work because `$sce` delegates to `$sceDelegate` for these operations.
16689          *
16690          * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
16691          *
16692          * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
16693          * can override it completely to change the behavior of `$sce`, the common case would
16694          * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
16695          * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
16696          * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
16697          * $sceDelegateProvider.resourceUrlWhitelist} and {@link
16698          * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16699          */
16700
16701         /**
16702          * @ngdoc provider
16703          * @name $sceDelegateProvider
16704          * @description
16705          *
16706          * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
16707          * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
16708          * that the URLs used for sourcing Angular templates are safe.  Refer {@link
16709          * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
16710          * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16711          *
16712          * For the general details about this service in Angular, read the main page for {@link ng.$sce
16713          * Strict Contextual Escaping (SCE)}.
16714          *
16715          * **Example**:  Consider the following case. <a name="example"></a>
16716          *
16717          * - your app is hosted at url `http://myapp.example.com/`
16718          * - but some of your templates are hosted on other domains you control such as
16719          *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
16720          * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
16721          *
16722          * Here is what a secure configuration for this scenario might look like:
16723          *
16724          * ```
16725          *  angular.module('myApp', []).config(function($sceDelegateProvider) {
16726          *    $sceDelegateProvider.resourceUrlWhitelist([
16727          *      // Allow same origin resource loads.
16728          *      'self',
16729          *      // Allow loading from our assets domain.  Notice the difference between * and **.
16730          *      'http://srv*.assets.example.com/**'
16731          *    ]);
16732          *
16733          *    // The blacklist overrides the whitelist so the open redirect here is blocked.
16734          *    $sceDelegateProvider.resourceUrlBlacklist([
16735          *      'http://myapp.example.com/clickThru**'
16736          *    ]);
16737          *  });
16738          * ```
16739          */
16740
16741         function $SceDelegateProvider() {
16742           this.SCE_CONTEXTS = SCE_CONTEXTS;
16743
16744           // Resource URLs can also be trusted by policy.
16745           var resourceUrlWhitelist = ['self'],
16746               resourceUrlBlacklist = [];
16747
16748           /**
16749            * @ngdoc method
16750            * @name $sceDelegateProvider#resourceUrlWhitelist
16751            * @kind function
16752            *
16753            * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
16754            *     provided.  This must be an array or null.  A snapshot of this array is used so further
16755            *     changes to the array are ignored.
16756            *
16757            *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16758            *     allowed in this array.
16759            *
16760            *     Note: **an empty whitelist array will block all URLs**!
16761            *
16762            * @return {Array} the currently set whitelist array.
16763            *
16764            * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
16765            * same origin resource requests.
16766            *
16767            * @description
16768            * Sets/Gets the whitelist of trusted resource URLs.
16769            */
16770           this.resourceUrlWhitelist = function(value) {
16771             if (arguments.length) {
16772               resourceUrlWhitelist = adjustMatchers(value);
16773             }
16774             return resourceUrlWhitelist;
16775           };
16776
16777           /**
16778            * @ngdoc method
16779            * @name $sceDelegateProvider#resourceUrlBlacklist
16780            * @kind function
16781            *
16782            * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
16783            *     provided.  This must be an array or null.  A snapshot of this array is used so further
16784            *     changes to the array are ignored.
16785            *
16786            *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16787            *     allowed in this array.
16788            *
16789            *     The typical usage for the blacklist is to **block
16790            *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
16791            *     these would otherwise be trusted but actually return content from the redirected domain.
16792            *
16793            *     Finally, **the blacklist overrides the whitelist** and has the final say.
16794            *
16795            * @return {Array} the currently set blacklist array.
16796            *
16797            * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
16798            * is no blacklist.)
16799            *
16800            * @description
16801            * Sets/Gets the blacklist of trusted resource URLs.
16802            */
16803
16804           this.resourceUrlBlacklist = function(value) {
16805             if (arguments.length) {
16806               resourceUrlBlacklist = adjustMatchers(value);
16807             }
16808             return resourceUrlBlacklist;
16809           };
16810
16811           this.$get = ['$injector', function($injector) {
16812
16813             var htmlSanitizer = function htmlSanitizer(html) {
16814               throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16815             };
16816
16817             if ($injector.has('$sanitize')) {
16818               htmlSanitizer = $injector.get('$sanitize');
16819             }
16820
16821
16822             function matchUrl(matcher, parsedUrl) {
16823               if (matcher === 'self') {
16824                 return urlIsSameOrigin(parsedUrl);
16825               } else {
16826                 // definitely a regex.  See adjustMatchers()
16827                 return !!matcher.exec(parsedUrl.href);
16828               }
16829             }
16830
16831             function isResourceUrlAllowedByPolicy(url) {
16832               var parsedUrl = urlResolve(url.toString());
16833               var i, n, allowed = false;
16834               // Ensure that at least one item from the whitelist allows this url.
16835               for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
16836                 if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
16837                   allowed = true;
16838                   break;
16839                 }
16840               }
16841               if (allowed) {
16842                 // Ensure that no item from the blacklist blocked this url.
16843                 for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
16844                   if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
16845                     allowed = false;
16846                     break;
16847                   }
16848                 }
16849               }
16850               return allowed;
16851             }
16852
16853             function generateHolderType(Base) {
16854               var holderType = function TrustedValueHolderType(trustedValue) {
16855                 this.$$unwrapTrustedValue = function() {
16856                   return trustedValue;
16857                 };
16858               };
16859               if (Base) {
16860                 holderType.prototype = new Base();
16861               }
16862               holderType.prototype.valueOf = function sceValueOf() {
16863                 return this.$$unwrapTrustedValue();
16864               };
16865               holderType.prototype.toString = function sceToString() {
16866                 return this.$$unwrapTrustedValue().toString();
16867               };
16868               return holderType;
16869             }
16870
16871             var trustedValueHolderBase = generateHolderType(),
16872                 byType = {};
16873
16874             byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
16875             byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
16876             byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
16877             byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
16878             byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
16879
16880             /**
16881              * @ngdoc method
16882              * @name $sceDelegate#trustAs
16883              *
16884              * @description
16885              * Returns an object that is trusted by angular for use in specified strict
16886              * contextual escaping contexts (such as ng-bind-html, ng-include, any src
16887              * attribute interpolation, any dom event binding attribute interpolation
16888              * such as for onclick,  etc.) that uses the provided value.
16889              * See {@link ng.$sce $sce} for enabling strict contextual escaping.
16890              *
16891              * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
16892              *   resourceUrl, html, js and css.
16893              * @param {*} value The value that that should be considered trusted/safe.
16894              * @returns {*} A value that can be used to stand in for the provided `value` in places
16895              * where Angular expects a $sce.trustAs() return value.
16896              */
16897             function trustAs(type, trustedValue) {
16898               var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16899               if (!Constructor) {
16900                 throw $sceMinErr('icontext',
16901                     'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
16902                     type, trustedValue);
16903               }
16904               if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
16905                 return trustedValue;
16906               }
16907               // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
16908               // mutable objects, we ensure here that the value passed in is actually a string.
16909               if (typeof trustedValue !== 'string') {
16910                 throw $sceMinErr('itype',
16911                     'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
16912                     type);
16913               }
16914               return new Constructor(trustedValue);
16915             }
16916
16917             /**
16918              * @ngdoc method
16919              * @name $sceDelegate#valueOf
16920              *
16921              * @description
16922              * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
16923              * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
16924              * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
16925              *
16926              * If the passed parameter is not a value that had been returned by {@link
16927              * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
16928              *
16929              * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
16930              *      call or anything else.
16931              * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
16932              *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
16933              *     `value` unchanged.
16934              */
16935             function valueOf(maybeTrusted) {
16936               if (maybeTrusted instanceof trustedValueHolderBase) {
16937                 return maybeTrusted.$$unwrapTrustedValue();
16938               } else {
16939                 return maybeTrusted;
16940               }
16941             }
16942
16943             /**
16944              * @ngdoc method
16945              * @name $sceDelegate#getTrusted
16946              *
16947              * @description
16948              * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
16949              * returns the originally supplied value if the queried context type is a supertype of the
16950              * created type.  If this condition isn't satisfied, throws an exception.
16951              *
16952              * @param {string} type The kind of context in which this value is to be used.
16953              * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
16954              *     `$sceDelegate.trustAs`} call.
16955              * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
16956              *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
16957              */
16958             function getTrusted(type, maybeTrusted) {
16959               if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
16960                 return maybeTrusted;
16961               }
16962               var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16963               if (constructor && maybeTrusted instanceof constructor) {
16964                 return maybeTrusted.$$unwrapTrustedValue();
16965               }
16966               // If we get here, then we may only take one of two actions.
16967               // 1. sanitize the value for the requested type, or
16968               // 2. throw an exception.
16969               if (type === SCE_CONTEXTS.RESOURCE_URL) {
16970                 if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
16971                   return maybeTrusted;
16972                 } else {
16973                   throw $sceMinErr('insecurl',
16974                       'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
16975                       maybeTrusted.toString());
16976                 }
16977               } else if (type === SCE_CONTEXTS.HTML) {
16978                 return htmlSanitizer(maybeTrusted);
16979               }
16980               throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16981             }
16982
16983             return { trustAs: trustAs,
16984                      getTrusted: getTrusted,
16985                      valueOf: valueOf };
16986           }];
16987         }
16988
16989
16990         /**
16991          * @ngdoc provider
16992          * @name $sceProvider
16993          * @description
16994          *
16995          * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
16996          * -   enable/disable Strict Contextual Escaping (SCE) in a module
16997          * -   override the default implementation with a custom delegate
16998          *
16999          * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
17000          */
17001
17002         /* jshint maxlen: false*/
17003
17004         /**
17005          * @ngdoc service
17006          * @name $sce
17007          * @kind function
17008          *
17009          * @description
17010          *
17011          * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
17012          *
17013          * # Strict Contextual Escaping
17014          *
17015          * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
17016          * contexts to result in a value that is marked as safe to use for that context.  One example of
17017          * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
17018          * to these contexts as privileged or SCE contexts.
17019          *
17020          * As of version 1.2, Angular ships with SCE enabled by default.
17021          *
17022          * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
17023          * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
17024          * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
17025          * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
17026          * to the top of your HTML document.
17027          *
17028          * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
17029          * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
17030          *
17031          * Here's an example of a binding in a privileged context:
17032          *
17033          * ```
17034          * <input ng-model="userHtml" aria-label="User input">
17035          * <div ng-bind-html="userHtml"></div>
17036          * ```
17037          *
17038          * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
17039          * disabled, this application allows the user to render arbitrary HTML into the DIV.
17040          * In a more realistic example, one may be rendering user comments, blog articles, etc. via
17041          * bindings.  (HTML is just one example of a context where rendering user controlled input creates
17042          * security vulnerabilities.)
17043          *
17044          * For the case of HTML, you might use a library, either on the client side, or on the server side,
17045          * to sanitize unsafe HTML before binding to the value and rendering it in the document.
17046          *
17047          * How would you ensure that every place that used these types of bindings was bound to a value that
17048          * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
17049          * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
17050          * properties/fields and forgot to update the binding to the sanitized value?
17051          *
17052          * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
17053          * determine that something explicitly says it's safe to use a value for binding in that
17054          * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
17055          * for those values that you can easily tell are safe - because they were received from your server,
17056          * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
17057          * allowing only the files in a specific directory to do this.  Ensuring that the internal API
17058          * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
17059          *
17060          * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
17061          * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
17062          * obtain values that will be accepted by SCE / privileged contexts.
17063          *
17064          *
17065          * ## How does it work?
17066          *
17067          * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
17068          * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
17069          * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
17070          * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
17071          *
17072          * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
17073          * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
17074          * simplified):
17075          *
17076          * ```
17077          * var ngBindHtmlDirective = ['$sce', function($sce) {
17078          *   return function(scope, element, attr) {
17079          *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
17080          *       element.html(value || '');
17081          *     });
17082          *   };
17083          * }];
17084          * ```
17085          *
17086          * ## Impact on loading templates
17087          *
17088          * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
17089          * `templateUrl`'s specified by {@link guide/directive directives}.
17090          *
17091          * By default, Angular only loads templates from the same domain and protocol as the application
17092          * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
17093          * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
17094          * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
17095          * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
17096          *
17097          * *Please note*:
17098          * The browser's
17099          * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
17100          * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
17101          * policy apply in addition to this and may further restrict whether the template is successfully
17102          * loaded.  This means that without the right CORS policy, loading templates from a different domain
17103          * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
17104          * browsers.
17105          *
17106          * ## This feels like too much overhead
17107          *
17108          * It's important to remember that SCE only applies to interpolation expressions.
17109          *
17110          * If your expressions are constant literals, they're automatically trusted and you don't need to
17111          * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
17112          * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
17113          *
17114          * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
17115          * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
17116          *
17117          * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
17118          * templates in `ng-include` from your application's domain without having to even know about SCE.
17119          * It blocks loading templates from other domains or loading templates over http from an https
17120          * served document.  You can change these by setting your own custom {@link
17121          * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
17122          * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
17123          *
17124          * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
17125          * application that's secure and can be audited to verify that with much more ease than bolting
17126          * security onto an application later.
17127          *
17128          * <a name="contexts"></a>
17129          * ## What trusted context types are supported?
17130          *
17131          * | Context             | Notes          |
17132          * |---------------------|----------------|
17133          * | `$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. |
17134          * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
17135          * | `$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. |
17136          * | `$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. |
17137          * | `$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. |
17138          *
17139          * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
17140          *
17141          *  Each element in these arrays must be one of the following:
17142          *
17143          *  - **'self'**
17144          *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
17145          *      domain** as the application document using the **same protocol**.
17146          *  - **String** (except the special value `'self'`)
17147          *    - The string is matched against the full *normalized / absolute URL* of the resource
17148          *      being tested (substring matches are not good enough.)
17149          *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
17150          *      match themselves.
17151          *    - `*`: matches zero or more occurrences of any character other than one of the following 6
17152          *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
17153          *      in a whitelist.
17154          *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
17155          *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
17156          *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
17157          *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
17158          *      http://foo.example.com/templates/**).
17159          *  - **RegExp** (*see caveat below*)
17160          *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
17161          *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
17162          *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
17163          *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
17164          *      small number of cases.  A `.` character in the regex used when matching the scheme or a
17165          *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
17166          *      is highly recommended to use the string patterns and only fall back to regular expressions
17167          *      as a last resort.
17168          *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
17169          *      matched against the **entire** *normalized / absolute URL* of the resource being tested
17170          *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
17171          *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
17172          *    - If you are generating your JavaScript from some other templating engine (not
17173          *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
17174          *      remember to escape your regular expression (and be aware that you might need more than
17175          *      one level of escaping depending on your templating engine and the way you interpolated
17176          *      the value.)  Do make use of your platform's escaping mechanism as it might be good
17177          *      enough before coding your own.  E.g. Ruby has
17178          *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
17179          *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
17180          *      Javascript lacks a similar built in function for escaping.  Take a look at Google
17181          *      Closure library's [goog.string.regExpEscape(s)](
17182          *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
17183          *
17184          * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
17185          *
17186          * ## Show me an example using SCE.
17187          *
17188          * <example module="mySceApp" deps="angular-sanitize.js">
17189          * <file name="index.html">
17190          *   <div ng-controller="AppController as myCtrl">
17191          *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
17192          *     <b>User comments</b><br>
17193          *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
17194          *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
17195          *     exploit.
17196          *     <div class="well">
17197          *       <div ng-repeat="userComment in myCtrl.userComments">
17198          *         <b>{{userComment.name}}</b>:
17199          *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
17200          *         <br>
17201          *       </div>
17202          *     </div>
17203          *   </div>
17204          * </file>
17205          *
17206          * <file name="script.js">
17207          *   angular.module('mySceApp', ['ngSanitize'])
17208          *     .controller('AppController', ['$http', '$templateCache', '$sce',
17209          *       function($http, $templateCache, $sce) {
17210          *         var self = this;
17211          *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
17212          *           self.userComments = userComments;
17213          *         });
17214          *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
17215          *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
17216          *             'sanitization.&quot;">Hover over this text.</span>');
17217          *       }]);
17218          * </file>
17219          *
17220          * <file name="test_data.json">
17221          * [
17222          *   { "name": "Alice",
17223          *     "htmlComment":
17224          *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
17225          *   },
17226          *   { "name": "Bob",
17227          *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
17228          *   }
17229          * ]
17230          * </file>
17231          *
17232          * <file name="protractor.js" type="protractor">
17233          *   describe('SCE doc demo', function() {
17234          *     it('should sanitize untrusted values', function() {
17235          *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
17236          *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
17237          *     });
17238          *
17239          *     it('should NOT sanitize explicitly trusted values', function() {
17240          *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
17241          *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
17242          *           'sanitization.&quot;">Hover over this text.</span>');
17243          *     });
17244          *   });
17245          * </file>
17246          * </example>
17247          *
17248          *
17249          *
17250          * ## Can I disable SCE completely?
17251          *
17252          * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
17253          * for little coding overhead.  It will be much harder to take an SCE disabled application and
17254          * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
17255          * for cases where you have a lot of existing code that was written before SCE was introduced and
17256          * you're migrating them a module at a time.
17257          *
17258          * That said, here's how you can completely disable SCE:
17259          *
17260          * ```
17261          * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
17262          *   // Completely disable SCE.  For demonstration purposes only!
17263          *   // Do not use in new projects.
17264          *   $sceProvider.enabled(false);
17265          * });
17266          * ```
17267          *
17268          */
17269         /* jshint maxlen: 100 */
17270
17271         function $SceProvider() {
17272           var enabled = true;
17273
17274           /**
17275            * @ngdoc method
17276            * @name $sceProvider#enabled
17277            * @kind function
17278            *
17279            * @param {boolean=} value If provided, then enables/disables SCE.
17280            * @return {boolean} true if SCE is enabled, false otherwise.
17281            *
17282            * @description
17283            * Enables/disables SCE and returns the current value.
17284            */
17285           this.enabled = function(value) {
17286             if (arguments.length) {
17287               enabled = !!value;
17288             }
17289             return enabled;
17290           };
17291
17292
17293           /* Design notes on the default implementation for SCE.
17294            *
17295            * The API contract for the SCE delegate
17296            * -------------------------------------
17297            * The SCE delegate object must provide the following 3 methods:
17298            *
17299            * - trustAs(contextEnum, value)
17300            *     This method is used to tell the SCE service that the provided value is OK to use in the
17301            *     contexts specified by contextEnum.  It must return an object that will be accepted by
17302            *     getTrusted() for a compatible contextEnum and return this value.
17303            *
17304            * - valueOf(value)
17305            *     For values that were not produced by trustAs(), return them as is.  For values that were
17306            *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
17307            *     trustAs is wrapping the given values into some type, this operation unwraps it when given
17308            *     such a value.
17309            *
17310            * - getTrusted(contextEnum, value)
17311            *     This function should return the a value that is safe to use in the context specified by
17312            *     contextEnum or throw and exception otherwise.
17313            *
17314            * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
17315            * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
17316            * instance, an implementation could maintain a registry of all trusted objects by context.  In
17317            * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
17318            * return the same object passed in if it was found in the registry under a compatible context or
17319            * throw an exception otherwise.  An implementation might only wrap values some of the time based
17320            * on some criteria.  getTrusted() might return a value and not throw an exception for special
17321            * constants or objects even if not wrapped.  All such implementations fulfill this contract.
17322            *
17323            *
17324            * A note on the inheritance model for SCE contexts
17325            * ------------------------------------------------
17326            * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
17327            * is purely an implementation details.
17328            *
17329            * The contract is simply this:
17330            *
17331            *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
17332            *     will also succeed.
17333            *
17334            * Inheritance happens to capture this in a natural way.  In some future, we
17335            * may not use inheritance anymore.  That is OK because no code outside of
17336            * sce.js and sceSpecs.js would need to be aware of this detail.
17337            */
17338
17339           this.$get = ['$parse', '$sceDelegate', function(
17340                         $parse,   $sceDelegate) {
17341             // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
17342             // the "expression(javascript expression)" syntax which is insecure.
17343             if (enabled && msie < 8) {
17344               throw $sceMinErr('iequirks',
17345                 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
17346                 'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
17347                 'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
17348             }
17349
17350             var sce = shallowCopy(SCE_CONTEXTS);
17351
17352             /**
17353              * @ngdoc method
17354              * @name $sce#isEnabled
17355              * @kind function
17356              *
17357              * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
17358              * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
17359              *
17360              * @description
17361              * Returns a boolean indicating if SCE is enabled.
17362              */
17363             sce.isEnabled = function() {
17364               return enabled;
17365             };
17366             sce.trustAs = $sceDelegate.trustAs;
17367             sce.getTrusted = $sceDelegate.getTrusted;
17368             sce.valueOf = $sceDelegate.valueOf;
17369
17370             if (!enabled) {
17371               sce.trustAs = sce.getTrusted = function(type, value) { return value; };
17372               sce.valueOf = identity;
17373             }
17374
17375             /**
17376              * @ngdoc method
17377              * @name $sce#parseAs
17378              *
17379              * @description
17380              * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
17381              * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
17382              * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
17383              * *result*)}
17384              *
17385              * @param {string} type The kind of SCE context in which this result will be used.
17386              * @param {string} expression String expression to compile.
17387              * @returns {function(context, locals)} a function which represents the compiled expression:
17388              *
17389              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17390              *      are evaluated against (typically a scope object).
17391              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17392              *      `context`.
17393              */
17394             sce.parseAs = function sceParseAs(type, expr) {
17395               var parsed = $parse(expr);
17396               if (parsed.literal && parsed.constant) {
17397                 return parsed;
17398               } else {
17399                 return $parse(expr, function(value) {
17400                   return sce.getTrusted(type, value);
17401                 });
17402               }
17403             };
17404
17405             /**
17406              * @ngdoc method
17407              * @name $sce#trustAs
17408              *
17409              * @description
17410              * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
17411              * returns an object that is trusted by angular for use in specified strict contextual
17412              * escaping contexts (such as ng-bind-html, ng-include, any src attribute
17413              * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
17414              * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
17415              * escaping.
17416              *
17417              * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
17418              *   resourceUrl, html, js and css.
17419              * @param {*} value The value that that should be considered trusted/safe.
17420              * @returns {*} A value that can be used to stand in for the provided `value` in places
17421              * where Angular expects a $sce.trustAs() return value.
17422              */
17423
17424             /**
17425              * @ngdoc method
17426              * @name $sce#trustAsHtml
17427              *
17428              * @description
17429              * Shorthand method.  `$sce.trustAsHtml(value)` →
17430              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
17431              *
17432              * @param {*} value The value to trustAs.
17433              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
17434              *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
17435              *     only accept expressions that are either literal constants or are the
17436              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17437              */
17438
17439             /**
17440              * @ngdoc method
17441              * @name $sce#trustAsUrl
17442              *
17443              * @description
17444              * Shorthand method.  `$sce.trustAsUrl(value)` →
17445              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
17446              *
17447              * @param {*} value The value to trustAs.
17448              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
17449              *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
17450              *     only accept expressions that are either literal constants or are the
17451              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17452              */
17453
17454             /**
17455              * @ngdoc method
17456              * @name $sce#trustAsResourceUrl
17457              *
17458              * @description
17459              * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
17460              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
17461              *
17462              * @param {*} value The value to trustAs.
17463              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
17464              *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
17465              *     only accept expressions that are either literal constants or are the return
17466              *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
17467              */
17468
17469             /**
17470              * @ngdoc method
17471              * @name $sce#trustAsJs
17472              *
17473              * @description
17474              * Shorthand method.  `$sce.trustAsJs(value)` →
17475              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
17476              *
17477              * @param {*} value The value to trustAs.
17478              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
17479              *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
17480              *     only accept expressions that are either literal constants or are the
17481              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17482              */
17483
17484             /**
17485              * @ngdoc method
17486              * @name $sce#getTrusted
17487              *
17488              * @description
17489              * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
17490              * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
17491              * originally supplied value if the queried context type is a supertype of the created type.
17492              * If this condition isn't satisfied, throws an exception.
17493              *
17494              * @param {string} type The kind of context in which this value is to be used.
17495              * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
17496              *                         call.
17497              * @returns {*} The value the was originally provided to
17498              *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
17499              *              Otherwise, throws an exception.
17500              */
17501
17502             /**
17503              * @ngdoc method
17504              * @name $sce#getTrustedHtml
17505              *
17506              * @description
17507              * Shorthand method.  `$sce.getTrustedHtml(value)` →
17508              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
17509              *
17510              * @param {*} value The value to pass to `$sce.getTrusted`.
17511              * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
17512              */
17513
17514             /**
17515              * @ngdoc method
17516              * @name $sce#getTrustedCss
17517              *
17518              * @description
17519              * Shorthand method.  `$sce.getTrustedCss(value)` →
17520              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
17521              *
17522              * @param {*} value The value to pass to `$sce.getTrusted`.
17523              * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
17524              */
17525
17526             /**
17527              * @ngdoc method
17528              * @name $sce#getTrustedUrl
17529              *
17530              * @description
17531              * Shorthand method.  `$sce.getTrustedUrl(value)` →
17532              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
17533              *
17534              * @param {*} value The value to pass to `$sce.getTrusted`.
17535              * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
17536              */
17537
17538             /**
17539              * @ngdoc method
17540              * @name $sce#getTrustedResourceUrl
17541              *
17542              * @description
17543              * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
17544              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
17545              *
17546              * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
17547              * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
17548              */
17549
17550             /**
17551              * @ngdoc method
17552              * @name $sce#getTrustedJs
17553              *
17554              * @description
17555              * Shorthand method.  `$sce.getTrustedJs(value)` →
17556              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
17557              *
17558              * @param {*} value The value to pass to `$sce.getTrusted`.
17559              * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
17560              */
17561
17562             /**
17563              * @ngdoc method
17564              * @name $sce#parseAsHtml
17565              *
17566              * @description
17567              * Shorthand method.  `$sce.parseAsHtml(expression string)` →
17568              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
17569              *
17570              * @param {string} expression String expression to compile.
17571              * @returns {function(context, locals)} a function which represents the compiled expression:
17572              *
17573              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17574              *      are evaluated against (typically a scope object).
17575              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17576              *      `context`.
17577              */
17578
17579             /**
17580              * @ngdoc method
17581              * @name $sce#parseAsCss
17582              *
17583              * @description
17584              * Shorthand method.  `$sce.parseAsCss(value)` →
17585              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
17586              *
17587              * @param {string} expression String expression to compile.
17588              * @returns {function(context, locals)} a function which represents the compiled expression:
17589              *
17590              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17591              *      are evaluated against (typically a scope object).
17592              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17593              *      `context`.
17594              */
17595
17596             /**
17597              * @ngdoc method
17598              * @name $sce#parseAsUrl
17599              *
17600              * @description
17601              * Shorthand method.  `$sce.parseAsUrl(value)` →
17602              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
17603              *
17604              * @param {string} expression String expression to compile.
17605              * @returns {function(context, locals)} a function which represents the compiled expression:
17606              *
17607              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17608              *      are evaluated against (typically a scope object).
17609              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17610              *      `context`.
17611              */
17612
17613             /**
17614              * @ngdoc method
17615              * @name $sce#parseAsResourceUrl
17616              *
17617              * @description
17618              * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
17619              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
17620              *
17621              * @param {string} expression String expression to compile.
17622              * @returns {function(context, locals)} a function which represents the compiled expression:
17623              *
17624              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17625              *      are evaluated against (typically a scope object).
17626              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17627              *      `context`.
17628              */
17629
17630             /**
17631              * @ngdoc method
17632              * @name $sce#parseAsJs
17633              *
17634              * @description
17635              * Shorthand method.  `$sce.parseAsJs(value)` →
17636              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
17637              *
17638              * @param {string} expression String expression to compile.
17639              * @returns {function(context, locals)} a function which represents the compiled expression:
17640              *
17641              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17642              *      are evaluated against (typically a scope object).
17643              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17644              *      `context`.
17645              */
17646
17647             // Shorthand delegations.
17648             var parse = sce.parseAs,
17649                 getTrusted = sce.getTrusted,
17650                 trustAs = sce.trustAs;
17651
17652             forEach(SCE_CONTEXTS, function(enumValue, name) {
17653               var lName = lowercase(name);
17654               sce[camelCase("parse_as_" + lName)] = function(expr) {
17655                 return parse(enumValue, expr);
17656               };
17657               sce[camelCase("get_trusted_" + lName)] = function(value) {
17658                 return getTrusted(enumValue, value);
17659               };
17660               sce[camelCase("trust_as_" + lName)] = function(value) {
17661                 return trustAs(enumValue, value);
17662               };
17663             });
17664
17665             return sce;
17666           }];
17667         }
17668
17669         /**
17670          * !!! This is an undocumented "private" service !!!
17671          *
17672          * @name $sniffer
17673          * @requires $window
17674          * @requires $document
17675          *
17676          * @property {boolean} history Does the browser support html5 history api ?
17677          * @property {boolean} transitions Does the browser support CSS transition events ?
17678          * @property {boolean} animations Does the browser support CSS animation events ?
17679          *
17680          * @description
17681          * This is very simple implementation of testing browser's features.
17682          */
17683         function $SnifferProvider() {
17684           this.$get = ['$window', '$document', function($window, $document) {
17685             var eventSupport = {},
17686                 android =
17687                   toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
17688                 boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
17689                 document = $document[0] || {},
17690                 vendorPrefix,
17691                 vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
17692                 bodyStyle = document.body && document.body.style,
17693                 transitions = false,
17694                 animations = false,
17695                 match;
17696
17697             if (bodyStyle) {
17698               for (var prop in bodyStyle) {
17699                 if (match = vendorRegex.exec(prop)) {
17700                   vendorPrefix = match[0];
17701                   vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
17702                   break;
17703                 }
17704               }
17705
17706               if (!vendorPrefix) {
17707                 vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
17708               }
17709
17710               transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
17711               animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
17712
17713               if (android && (!transitions ||  !animations)) {
17714                 transitions = isString(bodyStyle.webkitTransition);
17715                 animations = isString(bodyStyle.webkitAnimation);
17716               }
17717             }
17718
17719
17720             return {
17721               // Android has history.pushState, but it does not update location correctly
17722               // so let's not use the history API at all.
17723               // http://code.google.com/p/android/issues/detail?id=17471
17724               // https://github.com/angular/angular.js/issues/904
17725
17726               // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
17727               // so let's not use the history API also
17728               // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
17729               // jshint -W018
17730               history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
17731               // jshint +W018
17732               hasEvent: function(event) {
17733                 // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
17734                 // it. In particular the event is not fired when backspace or delete key are pressed or
17735                 // when cut operation is performed.
17736                 // IE10+ implements 'input' event but it erroneously fires under various situations,
17737                 // e.g. when placeholder changes, or a form is focused.
17738                 if (event === 'input' && msie <= 11) return false;
17739
17740                 if (isUndefined(eventSupport[event])) {
17741                   var divElm = document.createElement('div');
17742                   eventSupport[event] = 'on' + event in divElm;
17743                 }
17744
17745                 return eventSupport[event];
17746               },
17747               csp: csp(),
17748               vendorPrefix: vendorPrefix,
17749               transitions: transitions,
17750               animations: animations,
17751               android: android
17752             };
17753           }];
17754         }
17755
17756         var $compileMinErr = minErr('$compile');
17757
17758         /**
17759          * @ngdoc service
17760          * @name $templateRequest
17761          *
17762          * @description
17763          * The `$templateRequest` service runs security checks then downloads the provided template using
17764          * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
17765          * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
17766          * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
17767          * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
17768          * when `tpl` is of type string and `$templateCache` has the matching entry.
17769          *
17770          * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
17771          * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
17772          *
17773          * @return {Promise} a promise for the HTTP response data of the given URL.
17774          *
17775          * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
17776          */
17777         function $TemplateRequestProvider() {
17778           this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
17779             function handleRequestFn(tpl, ignoreRequestError) {
17780               handleRequestFn.totalPendingRequests++;
17781
17782               // We consider the template cache holds only trusted templates, so
17783               // there's no need to go through whitelisting again for keys that already
17784               // are included in there. This also makes Angular accept any script
17785               // directive, no matter its name. However, we still need to unwrap trusted
17786               // types.
17787               if (!isString(tpl) || !$templateCache.get(tpl)) {
17788                 tpl = $sce.getTrustedResourceUrl(tpl);
17789               }
17790
17791               var transformResponse = $http.defaults && $http.defaults.transformResponse;
17792
17793               if (isArray(transformResponse)) {
17794                 transformResponse = transformResponse.filter(function(transformer) {
17795                   return transformer !== defaultHttpResponseTransform;
17796                 });
17797               } else if (transformResponse === defaultHttpResponseTransform) {
17798                 transformResponse = null;
17799               }
17800
17801               var httpOptions = {
17802                 cache: $templateCache,
17803                 transformResponse: transformResponse
17804               };
17805
17806               return $http.get(tpl, httpOptions)
17807                 ['finally'](function() {
17808                   handleRequestFn.totalPendingRequests--;
17809                 })
17810                 .then(function(response) {
17811                   $templateCache.put(tpl, response.data);
17812                   return response.data;
17813                 }, handleError);
17814
17815               function handleError(resp) {
17816                 if (!ignoreRequestError) {
17817                   throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
17818                     tpl, resp.status, resp.statusText);
17819                 }
17820                 return $q.reject(resp);
17821               }
17822             }
17823
17824             handleRequestFn.totalPendingRequests = 0;
17825
17826             return handleRequestFn;
17827           }];
17828         }
17829
17830         function $$TestabilityProvider() {
17831           this.$get = ['$rootScope', '$browser', '$location',
17832                function($rootScope,   $browser,   $location) {
17833
17834             /**
17835              * @name $testability
17836              *
17837              * @description
17838              * The private $$testability service provides a collection of methods for use when debugging
17839              * or by automated test and debugging tools.
17840              */
17841             var testability = {};
17842
17843             /**
17844              * @name $$testability#findBindings
17845              *
17846              * @description
17847              * Returns an array of elements that are bound (via ng-bind or {{}})
17848              * to expressions matching the input.
17849              *
17850              * @param {Element} element The element root to search from.
17851              * @param {string} expression The binding expression to match.
17852              * @param {boolean} opt_exactMatch If true, only returns exact matches
17853              *     for the expression. Filters and whitespace are ignored.
17854              */
17855             testability.findBindings = function(element, expression, opt_exactMatch) {
17856               var bindings = element.getElementsByClassName('ng-binding');
17857               var matches = [];
17858               forEach(bindings, function(binding) {
17859                 var dataBinding = angular.element(binding).data('$binding');
17860                 if (dataBinding) {
17861                   forEach(dataBinding, function(bindingName) {
17862                     if (opt_exactMatch) {
17863                       var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
17864                       if (matcher.test(bindingName)) {
17865                         matches.push(binding);
17866                       }
17867                     } else {
17868                       if (bindingName.indexOf(expression) != -1) {
17869                         matches.push(binding);
17870                       }
17871                     }
17872                   });
17873                 }
17874               });
17875               return matches;
17876             };
17877
17878             /**
17879              * @name $$testability#findModels
17880              *
17881              * @description
17882              * Returns an array of elements that are two-way found via ng-model to
17883              * expressions matching the input.
17884              *
17885              * @param {Element} element The element root to search from.
17886              * @param {string} expression The model expression to match.
17887              * @param {boolean} opt_exactMatch If true, only returns exact matches
17888              *     for the expression.
17889              */
17890             testability.findModels = function(element, expression, opt_exactMatch) {
17891               var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
17892               for (var p = 0; p < prefixes.length; ++p) {
17893                 var attributeEquals = opt_exactMatch ? '=' : '*=';
17894                 var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
17895                 var elements = element.querySelectorAll(selector);
17896                 if (elements.length) {
17897                   return elements;
17898                 }
17899               }
17900             };
17901
17902             /**
17903              * @name $$testability#getLocation
17904              *
17905              * @description
17906              * Shortcut for getting the location in a browser agnostic way. Returns
17907              *     the path, search, and hash. (e.g. /path?a=b#hash)
17908              */
17909             testability.getLocation = function() {
17910               return $location.url();
17911             };
17912
17913             /**
17914              * @name $$testability#setLocation
17915              *
17916              * @description
17917              * Shortcut for navigating to a location without doing a full page reload.
17918              *
17919              * @param {string} url The location url (path, search and hash,
17920              *     e.g. /path?a=b#hash) to go to.
17921              */
17922             testability.setLocation = function(url) {
17923               if (url !== $location.url()) {
17924                 $location.url(url);
17925                 $rootScope.$digest();
17926               }
17927             };
17928
17929             /**
17930              * @name $$testability#whenStable
17931              *
17932              * @description
17933              * Calls the callback when $timeout and $http requests are completed.
17934              *
17935              * @param {function} callback
17936              */
17937             testability.whenStable = function(callback) {
17938               $browser.notifyWhenNoOutstandingRequests(callback);
17939             };
17940
17941             return testability;
17942           }];
17943         }
17944
17945         function $TimeoutProvider() {
17946           this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
17947                function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
17948
17949             var deferreds = {};
17950
17951
17952              /**
17953               * @ngdoc service
17954               * @name $timeout
17955               *
17956               * @description
17957               * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
17958               * block and delegates any exceptions to
17959               * {@link ng.$exceptionHandler $exceptionHandler} service.
17960               *
17961               * The return value of calling `$timeout` is a promise, which will be resolved when
17962               * the delay has passed and the timeout function, if provided, is executed.
17963               *
17964               * To cancel a timeout request, call `$timeout.cancel(promise)`.
17965               *
17966               * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
17967               * synchronously flush the queue of deferred functions.
17968               *
17969               * If you only want a promise that will be resolved after some specified delay
17970               * then you can call `$timeout` without the `fn` function.
17971               *
17972               * @param {function()=} fn A function, whose execution should be delayed.
17973               * @param {number=} [delay=0] Delay in milliseconds.
17974               * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
17975               *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
17976               * @param {...*=} Pass additional parameters to the executed function.
17977               * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
17978               *   promise will be resolved with is the return value of the `fn` function.
17979               *
17980               */
17981             function timeout(fn, delay, invokeApply) {
17982               if (!isFunction(fn)) {
17983                 invokeApply = delay;
17984                 delay = fn;
17985                 fn = noop;
17986               }
17987
17988               var args = sliceArgs(arguments, 3),
17989                   skipApply = (isDefined(invokeApply) && !invokeApply),
17990                   deferred = (skipApply ? $$q : $q).defer(),
17991                   promise = deferred.promise,
17992                   timeoutId;
17993
17994               timeoutId = $browser.defer(function() {
17995                 try {
17996                   deferred.resolve(fn.apply(null, args));
17997                 } catch (e) {
17998                   deferred.reject(e);
17999                   $exceptionHandler(e);
18000                 }
18001                 finally {
18002                   delete deferreds[promise.$$timeoutId];
18003                 }
18004
18005                 if (!skipApply) $rootScope.$apply();
18006               }, delay);
18007
18008               promise.$$timeoutId = timeoutId;
18009               deferreds[timeoutId] = deferred;
18010
18011               return promise;
18012             }
18013
18014
18015              /**
18016               * @ngdoc method
18017               * @name $timeout#cancel
18018               *
18019               * @description
18020               * Cancels a task associated with the `promise`. As a result of this, the promise will be
18021               * resolved with a rejection.
18022               *
18023               * @param {Promise=} promise Promise returned by the `$timeout` function.
18024               * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
18025               *   canceled.
18026               */
18027             timeout.cancel = function(promise) {
18028               if (promise && promise.$$timeoutId in deferreds) {
18029                 deferreds[promise.$$timeoutId].reject('canceled');
18030                 delete deferreds[promise.$$timeoutId];
18031                 return $browser.defer.cancel(promise.$$timeoutId);
18032               }
18033               return false;
18034             };
18035
18036             return timeout;
18037           }];
18038         }
18039
18040         // NOTE:  The usage of window and document instead of $window and $document here is
18041         // deliberate.  This service depends on the specific behavior of anchor nodes created by the
18042         // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
18043         // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
18044         // doesn't know about mocked locations and resolves URLs to the real document - which is
18045         // exactly the behavior needed here.  There is little value is mocking these out for this
18046         // service.
18047         var urlParsingNode = document.createElement("a");
18048         var originUrl = urlResolve(window.location.href);
18049
18050
18051         /**
18052          *
18053          * Implementation Notes for non-IE browsers
18054          * ----------------------------------------
18055          * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
18056          * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
18057          * URL will be resolved into an absolute URL in the context of the application document.
18058          * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
18059          * properties are all populated to reflect the normalized URL.  This approach has wide
18060          * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
18061          * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
18062          *
18063          * Implementation Notes for IE
18064          * ---------------------------
18065          * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
18066          * browsers.  However, the parsed components will not be set if the URL assigned did not specify
18067          * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
18068          * work around that by performing the parsing in a 2nd step by taking a previously normalized
18069          * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
18070          * properties such as protocol, hostname, port, etc.
18071          *
18072          * References:
18073          *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
18074          *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
18075          *   http://url.spec.whatwg.org/#urlutils
18076          *   https://github.com/angular/angular.js/pull/2902
18077          *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
18078          *
18079          * @kind function
18080          * @param {string} url The URL to be parsed.
18081          * @description Normalizes and parses a URL.
18082          * @returns {object} Returns the normalized URL as a dictionary.
18083          *
18084          *   | member name   | Description    |
18085          *   |---------------|----------------|
18086          *   | href          | A normalized version of the provided URL if it was not an absolute URL |
18087          *   | protocol      | The protocol including the trailing colon                              |
18088          *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
18089          *   | search        | The search params, minus the question mark                             |
18090          *   | hash          | The hash string, minus the hash symbol
18091          *   | hostname      | The hostname
18092          *   | port          | The port, without ":"
18093          *   | pathname      | The pathname, beginning with "/"
18094          *
18095          */
18096         function urlResolve(url) {
18097           var href = url;
18098
18099           if (msie) {
18100             // Normalize before parse.  Refer Implementation Notes on why this is
18101             // done in two steps on IE.
18102             urlParsingNode.setAttribute("href", href);
18103             href = urlParsingNode.href;
18104           }
18105
18106           urlParsingNode.setAttribute('href', href);
18107
18108           // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
18109           return {
18110             href: urlParsingNode.href,
18111             protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
18112             host: urlParsingNode.host,
18113             search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
18114             hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
18115             hostname: urlParsingNode.hostname,
18116             port: urlParsingNode.port,
18117             pathname: (urlParsingNode.pathname.charAt(0) === '/')
18118               ? urlParsingNode.pathname
18119               : '/' + urlParsingNode.pathname
18120           };
18121         }
18122
18123         /**
18124          * Parse a request URL and determine whether this is a same-origin request as the application document.
18125          *
18126          * @param {string|object} requestUrl The url of the request as a string that will be resolved
18127          * or a parsed URL object.
18128          * @returns {boolean} Whether the request is for the same origin as the application document.
18129          */
18130         function urlIsSameOrigin(requestUrl) {
18131           var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
18132           return (parsed.protocol === originUrl.protocol &&
18133                   parsed.host === originUrl.host);
18134         }
18135
18136         /**
18137          * @ngdoc service
18138          * @name $window
18139          *
18140          * @description
18141          * A reference to the browser's `window` object. While `window`
18142          * is globally available in JavaScript, it causes testability problems, because
18143          * it is a global variable. In angular we always refer to it through the
18144          * `$window` service, so it may be overridden, removed or mocked for testing.
18145          *
18146          * Expressions, like the one defined for the `ngClick` directive in the example
18147          * below, are evaluated with respect to the current scope.  Therefore, there is
18148          * no risk of inadvertently coding in a dependency on a global value in such an
18149          * expression.
18150          *
18151          * @example
18152            <example module="windowExample">
18153              <file name="index.html">
18154                <script>
18155                  angular.module('windowExample', [])
18156                    .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
18157                      $scope.greeting = 'Hello, World!';
18158                      $scope.doGreeting = function(greeting) {
18159                        $window.alert(greeting);
18160                      };
18161                    }]);
18162                </script>
18163                <div ng-controller="ExampleController">
18164                  <input type="text" ng-model="greeting" aria-label="greeting" />
18165                  <button ng-click="doGreeting(greeting)">ALERT</button>
18166                </div>
18167              </file>
18168              <file name="protractor.js" type="protractor">
18169               it('should display the greeting in the input box', function() {
18170                element(by.model('greeting')).sendKeys('Hello, E2E Tests');
18171                // If we click the button it will block the test runner
18172                // element(':button').click();
18173               });
18174              </file>
18175            </example>
18176          */
18177         function $WindowProvider() {
18178           this.$get = valueFn(window);
18179         }
18180
18181         /**
18182          * @name $$cookieReader
18183          * @requires $document
18184          *
18185          * @description
18186          * This is a private service for reading cookies used by $http and ngCookies
18187          *
18188          * @return {Object} a key/value map of the current cookies
18189          */
18190         function $$CookieReader($document) {
18191           var rawDocument = $document[0] || {};
18192           var lastCookies = {};
18193           var lastCookieString = '';
18194
18195           function safeDecodeURIComponent(str) {
18196             try {
18197               return decodeURIComponent(str);
18198             } catch (e) {
18199               return str;
18200             }
18201           }
18202
18203           return function() {
18204             var cookieArray, cookie, i, index, name;
18205             var currentCookieString = rawDocument.cookie || '';
18206
18207             if (currentCookieString !== lastCookieString) {
18208               lastCookieString = currentCookieString;
18209               cookieArray = lastCookieString.split('; ');
18210               lastCookies = {};
18211
18212               for (i = 0; i < cookieArray.length; i++) {
18213                 cookie = cookieArray[i];
18214                 index = cookie.indexOf('=');
18215                 if (index > 0) { //ignore nameless cookies
18216                   name = safeDecodeURIComponent(cookie.substring(0, index));
18217                   // the first value that is seen for a cookie is the most
18218                   // specific one.  values for the same cookie name that
18219                   // follow are for less specific paths.
18220                   if (isUndefined(lastCookies[name])) {
18221                     lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
18222                   }
18223                 }
18224               }
18225             }
18226             return lastCookies;
18227           };
18228         }
18229
18230         $$CookieReader.$inject = ['$document'];
18231
18232         function $$CookieReaderProvider() {
18233           this.$get = $$CookieReader;
18234         }
18235
18236         /* global currencyFilter: true,
18237          dateFilter: true,
18238          filterFilter: true,
18239          jsonFilter: true,
18240          limitToFilter: true,
18241          lowercaseFilter: true,
18242          numberFilter: true,
18243          orderByFilter: true,
18244          uppercaseFilter: true,
18245          */
18246
18247         /**
18248          * @ngdoc provider
18249          * @name $filterProvider
18250          * @description
18251          *
18252          * Filters are just functions which transform input to an output. However filters need to be
18253          * Dependency Injected. To achieve this a filter definition consists of a factory function which is
18254          * annotated with dependencies and is responsible for creating a filter function.
18255          *
18256          * <div class="alert alert-warning">
18257          * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
18258          * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
18259          * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
18260          * (`myapp_subsection_filterx`).
18261          * </div>
18262          *
18263          * ```js
18264          *   // Filter registration
18265          *   function MyModule($provide, $filterProvider) {
18266          *     // create a service to demonstrate injection (not always needed)
18267          *     $provide.value('greet', function(name){
18268          *       return 'Hello ' + name + '!';
18269          *     });
18270          *
18271          *     // register a filter factory which uses the
18272          *     // greet service to demonstrate DI.
18273          *     $filterProvider.register('greet', function(greet){
18274          *       // return the filter function which uses the greet service
18275          *       // to generate salutation
18276          *       return function(text) {
18277          *         // filters need to be forgiving so check input validity
18278          *         return text && greet(text) || text;
18279          *       };
18280          *     });
18281          *   }
18282          * ```
18283          *
18284          * The filter function is registered with the `$injector` under the filter name suffix with
18285          * `Filter`.
18286          *
18287          * ```js
18288          *   it('should be the same instance', inject(
18289          *     function($filterProvider) {
18290          *       $filterProvider.register('reverse', function(){
18291          *         return ...;
18292          *       });
18293          *     },
18294          *     function($filter, reverseFilter) {
18295          *       expect($filter('reverse')).toBe(reverseFilter);
18296          *     });
18297          * ```
18298          *
18299          *
18300          * For more information about how angular filters work, and how to create your own filters, see
18301          * {@link guide/filter Filters} in the Angular Developer Guide.
18302          */
18303
18304         /**
18305          * @ngdoc service
18306          * @name $filter
18307          * @kind function
18308          * @description
18309          * Filters are used for formatting data displayed to the user.
18310          *
18311          * The general syntax in templates is as follows:
18312          *
18313          *         {{ expression [| filter_name[:parameter_value] ... ] }}
18314          *
18315          * @param {String} name Name of the filter function to retrieve
18316          * @return {Function} the filter function
18317          * @example
18318            <example name="$filter" module="filterExample">
18319              <file name="index.html">
18320                <div ng-controller="MainCtrl">
18321                 <h3>{{ originalText }}</h3>
18322                 <h3>{{ filteredText }}</h3>
18323                </div>
18324              </file>
18325
18326              <file name="script.js">
18327               angular.module('filterExample', [])
18328               .controller('MainCtrl', function($scope, $filter) {
18329                 $scope.originalText = 'hello';
18330                 $scope.filteredText = $filter('uppercase')($scope.originalText);
18331               });
18332              </file>
18333            </example>
18334           */
18335         $FilterProvider.$inject = ['$provide'];
18336         function $FilterProvider($provide) {
18337           var suffix = 'Filter';
18338
18339           /**
18340            * @ngdoc method
18341            * @name $filterProvider#register
18342            * @param {string|Object} name Name of the filter function, or an object map of filters where
18343            *    the keys are the filter names and the values are the filter factories.
18344            *
18345            *    <div class="alert alert-warning">
18346            *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
18347            *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
18348            *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
18349            *    (`myapp_subsection_filterx`).
18350            *    </div>
18351             * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
18352            * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
18353            *    of the registered filter instances.
18354            */
18355           function register(name, factory) {
18356             if (isObject(name)) {
18357               var filters = {};
18358               forEach(name, function(filter, key) {
18359                 filters[key] = register(key, filter);
18360               });
18361               return filters;
18362             } else {
18363               return $provide.factory(name + suffix, factory);
18364             }
18365           }
18366           this.register = register;
18367
18368           this.$get = ['$injector', function($injector) {
18369             return function(name) {
18370               return $injector.get(name + suffix);
18371             };
18372           }];
18373
18374           ////////////////////////////////////////
18375
18376           /* global
18377             currencyFilter: false,
18378             dateFilter: false,
18379             filterFilter: false,
18380             jsonFilter: false,
18381             limitToFilter: false,
18382             lowercaseFilter: false,
18383             numberFilter: false,
18384             orderByFilter: false,
18385             uppercaseFilter: false,
18386           */
18387
18388           register('currency', currencyFilter);
18389           register('date', dateFilter);
18390           register('filter', filterFilter);
18391           register('json', jsonFilter);
18392           register('limitTo', limitToFilter);
18393           register('lowercase', lowercaseFilter);
18394           register('number', numberFilter);
18395           register('orderBy', orderByFilter);
18396           register('uppercase', uppercaseFilter);
18397         }
18398
18399         /**
18400          * @ngdoc filter
18401          * @name filter
18402          * @kind function
18403          *
18404          * @description
18405          * Selects a subset of items from `array` and returns it as a new array.
18406          *
18407          * @param {Array} array The source array.
18408          * @param {string|Object|function()} expression The predicate to be used for selecting items from
18409          *   `array`.
18410          *
18411          *   Can be one of:
18412          *
18413          *   - `string`: The string is used for matching against the contents of the `array`. All strings or
18414          *     objects with string properties in `array` that match this string will be returned. This also
18415          *     applies to nested object properties.
18416          *     The predicate can be negated by prefixing the string with `!`.
18417          *
18418          *   - `Object`: A pattern object can be used to filter specific properties on objects contained
18419          *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
18420          *     which have property `name` containing "M" and property `phone` containing "1". A special
18421          *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
18422          *     property of the object or its nested object properties. That's equivalent to the simple
18423          *     substring match with a `string` as described above. The predicate can be negated by prefixing
18424          *     the string with `!`.
18425          *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
18426          *     not containing "M".
18427          *
18428          *     Note that a named property will match properties on the same level only, while the special
18429          *     `$` property will match properties on the same level or deeper. E.g. an array item like
18430          *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
18431          *     **will** be matched by `{$: 'John'}`.
18432          *
18433          *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
18434          *     The function is called for each element of the array, with the element, its index, and
18435          *     the entire array itself as arguments.
18436          *
18437          *     The final result is an array of those elements that the predicate returned true for.
18438          *
18439          * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
18440          *     determining if the expected value (from the filter expression) and actual value (from
18441          *     the object in the array) should be considered a match.
18442          *
18443          *   Can be one of:
18444          *
18445          *   - `function(actual, expected)`:
18446          *     The function will be given the object value and the predicate value to compare and
18447          *     should return true if both values should be considered equal.
18448          *
18449          *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
18450          *     This is essentially strict comparison of expected and actual.
18451          *
18452          *   - `false|undefined`: A short hand for a function which will look for a substring match in case
18453          *     insensitive way.
18454          *
18455          *     Primitive values are converted to strings. Objects are not compared against primitives,
18456          *     unless they have a custom `toString` method (e.g. `Date` objects).
18457          *
18458          * @example
18459            <example>
18460              <file name="index.html">
18461                <div ng-init="friends = [{name:'John', phone:'555-1276'},
18462                                         {name:'Mary', phone:'800-BIG-MARY'},
18463                                         {name:'Mike', phone:'555-4321'},
18464                                         {name:'Adam', phone:'555-5678'},
18465                                         {name:'Julie', phone:'555-8765'},
18466                                         {name:'Juliette', phone:'555-5678'}]"></div>
18467
18468                <label>Search: <input ng-model="searchText"></label>
18469                <table id="searchTextResults">
18470                  <tr><th>Name</th><th>Phone</th></tr>
18471                  <tr ng-repeat="friend in friends | filter:searchText">
18472                    <td>{{friend.name}}</td>
18473                    <td>{{friend.phone}}</td>
18474                  </tr>
18475                </table>
18476                <hr>
18477                <label>Any: <input ng-model="search.$"></label> <br>
18478                <label>Name only <input ng-model="search.name"></label><br>
18479                <label>Phone only <input ng-model="search.phone"></label><br>
18480                <label>Equality <input type="checkbox" ng-model="strict"></label><br>
18481                <table id="searchObjResults">
18482                  <tr><th>Name</th><th>Phone</th></tr>
18483                  <tr ng-repeat="friendObj in friends | filter:search:strict">
18484                    <td>{{friendObj.name}}</td>
18485                    <td>{{friendObj.phone}}</td>
18486                  </tr>
18487                </table>
18488              </file>
18489              <file name="protractor.js" type="protractor">
18490                var expectFriendNames = function(expectedNames, key) {
18491                  element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
18492                    arr.forEach(function(wd, i) {
18493                      expect(wd.getText()).toMatch(expectedNames[i]);
18494                    });
18495                  });
18496                };
18497
18498                it('should search across all fields when filtering with a string', function() {
18499                  var searchText = element(by.model('searchText'));
18500                  searchText.clear();
18501                  searchText.sendKeys('m');
18502                  expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
18503
18504                  searchText.clear();
18505                  searchText.sendKeys('76');
18506                  expectFriendNames(['John', 'Julie'], 'friend');
18507                });
18508
18509                it('should search in specific fields when filtering with a predicate object', function() {
18510                  var searchAny = element(by.model('search.$'));
18511                  searchAny.clear();
18512                  searchAny.sendKeys('i');
18513                  expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
18514                });
18515                it('should use a equal comparison when comparator is true', function() {
18516                  var searchName = element(by.model('search.name'));
18517                  var strict = element(by.model('strict'));
18518                  searchName.clear();
18519                  searchName.sendKeys('Julie');
18520                  strict.click();
18521                  expectFriendNames(['Julie'], 'friendObj');
18522                });
18523              </file>
18524            </example>
18525          */
18526         function filterFilter() {
18527           return function(array, expression, comparator) {
18528             if (!isArrayLike(array)) {
18529               if (array == null) {
18530                 return array;
18531               } else {
18532                 throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
18533               }
18534             }
18535
18536             var expressionType = getTypeForFilter(expression);
18537             var predicateFn;
18538             var matchAgainstAnyProp;
18539
18540             switch (expressionType) {
18541               case 'function':
18542                 predicateFn = expression;
18543                 break;
18544               case 'boolean':
18545               case 'null':
18546               case 'number':
18547               case 'string':
18548                 matchAgainstAnyProp = true;
18549                 //jshint -W086
18550               case 'object':
18551                 //jshint +W086
18552                 predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
18553                 break;
18554               default:
18555                 return array;
18556             }
18557
18558             return Array.prototype.filter.call(array, predicateFn);
18559           };
18560         }
18561
18562         // Helper functions for `filterFilter`
18563         function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
18564           var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
18565           var predicateFn;
18566
18567           if (comparator === true) {
18568             comparator = equals;
18569           } else if (!isFunction(comparator)) {
18570             comparator = function(actual, expected) {
18571               if (isUndefined(actual)) {
18572                 // No substring matching against `undefined`
18573                 return false;
18574               }
18575               if ((actual === null) || (expected === null)) {
18576                 // No substring matching against `null`; only match against `null`
18577                 return actual === expected;
18578               }
18579               if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
18580                 // Should not compare primitives against objects, unless they have custom `toString` method
18581                 return false;
18582               }
18583
18584               actual = lowercase('' + actual);
18585               expected = lowercase('' + expected);
18586               return actual.indexOf(expected) !== -1;
18587             };
18588           }
18589
18590           predicateFn = function(item) {
18591             if (shouldMatchPrimitives && !isObject(item)) {
18592               return deepCompare(item, expression.$, comparator, false);
18593             }
18594             return deepCompare(item, expression, comparator, matchAgainstAnyProp);
18595           };
18596
18597           return predicateFn;
18598         }
18599
18600         function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
18601           var actualType = getTypeForFilter(actual);
18602           var expectedType = getTypeForFilter(expected);
18603
18604           if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
18605             return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
18606           } else if (isArray(actual)) {
18607             // In case `actual` is an array, consider it a match
18608             // if ANY of it's items matches `expected`
18609             return actual.some(function(item) {
18610               return deepCompare(item, expected, comparator, matchAgainstAnyProp);
18611             });
18612           }
18613
18614           switch (actualType) {
18615             case 'object':
18616               var key;
18617               if (matchAgainstAnyProp) {
18618                 for (key in actual) {
18619                   if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
18620                     return true;
18621                   }
18622                 }
18623                 return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
18624               } else if (expectedType === 'object') {
18625                 for (key in expected) {
18626                   var expectedVal = expected[key];
18627                   if (isFunction(expectedVal) || isUndefined(expectedVal)) {
18628                     continue;
18629                   }
18630
18631                   var matchAnyProperty = key === '$';
18632                   var actualVal = matchAnyProperty ? actual : actual[key];
18633                   if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
18634                     return false;
18635                   }
18636                 }
18637                 return true;
18638               } else {
18639                 return comparator(actual, expected);
18640               }
18641               break;
18642             case 'function':
18643               return false;
18644             default:
18645               return comparator(actual, expected);
18646           }
18647         }
18648
18649         // Used for easily differentiating between `null` and actual `object`
18650         function getTypeForFilter(val) {
18651           return (val === null) ? 'null' : typeof val;
18652         }
18653
18654         /**
18655          * @ngdoc filter
18656          * @name currency
18657          * @kind function
18658          *
18659          * @description
18660          * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
18661          * symbol for current locale is used.
18662          *
18663          * @param {number} amount Input to filter.
18664          * @param {string=} symbol Currency symbol or identifier to be displayed.
18665          * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
18666          * @returns {string} Formatted number.
18667          *
18668          *
18669          * @example
18670            <example module="currencyExample">
18671              <file name="index.html">
18672                <script>
18673                  angular.module('currencyExample', [])
18674                    .controller('ExampleController', ['$scope', function($scope) {
18675                      $scope.amount = 1234.56;
18676                    }]);
18677                </script>
18678                <div ng-controller="ExampleController">
18679                  <input type="number" ng-model="amount" aria-label="amount"> <br>
18680                  default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
18681                  custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
18682                  no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
18683                </div>
18684              </file>
18685              <file name="protractor.js" type="protractor">
18686                it('should init with 1234.56', function() {
18687                  expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
18688                  expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
18689                  expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
18690                });
18691                it('should update', function() {
18692                  if (browser.params.browser == 'safari') {
18693                    // Safari does not understand the minus key. See
18694                    // https://github.com/angular/protractor/issues/481
18695                    return;
18696                  }
18697                  element(by.model('amount')).clear();
18698                  element(by.model('amount')).sendKeys('-1234');
18699                  expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
18700                  expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
18701                  expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
18702                });
18703              </file>
18704            </example>
18705          */
18706         currencyFilter.$inject = ['$locale'];
18707         function currencyFilter($locale) {
18708           var formats = $locale.NUMBER_FORMATS;
18709           return function(amount, currencySymbol, fractionSize) {
18710             if (isUndefined(currencySymbol)) {
18711               currencySymbol = formats.CURRENCY_SYM;
18712             }
18713
18714             if (isUndefined(fractionSize)) {
18715               fractionSize = formats.PATTERNS[1].maxFrac;
18716             }
18717
18718             // if null or undefined pass it through
18719             return (amount == null)
18720                 ? amount
18721                 : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
18722                     replace(/\u00A4/g, currencySymbol);
18723           };
18724         }
18725
18726         /**
18727          * @ngdoc filter
18728          * @name number
18729          * @kind function
18730          *
18731          * @description
18732          * Formats a number as text.
18733          *
18734          * If the input is null or undefined, it will just be returned.
18735          * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
18736          * If the input is not a number an empty string is returned.
18737          *
18738          *
18739          * @param {number|string} number Number to format.
18740          * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
18741          * If this is not provided then the fraction size is computed from the current locale's number
18742          * formatting pattern. In the case of the default locale, it will be 3.
18743          * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
18744          *
18745          * @example
18746            <example module="numberFilterExample">
18747              <file name="index.html">
18748                <script>
18749                  angular.module('numberFilterExample', [])
18750                    .controller('ExampleController', ['$scope', function($scope) {
18751                      $scope.val = 1234.56789;
18752                    }]);
18753                </script>
18754                <div ng-controller="ExampleController">
18755                  <label>Enter number: <input ng-model='val'></label><br>
18756                  Default formatting: <span id='number-default'>{{val | number}}</span><br>
18757                  No fractions: <span>{{val | number:0}}</span><br>
18758                  Negative number: <span>{{-val | number:4}}</span>
18759                </div>
18760              </file>
18761              <file name="protractor.js" type="protractor">
18762                it('should format numbers', function() {
18763                  expect(element(by.id('number-default')).getText()).toBe('1,234.568');
18764                  expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
18765                  expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
18766                });
18767
18768                it('should update', function() {
18769                  element(by.model('val')).clear();
18770                  element(by.model('val')).sendKeys('3374.333');
18771                  expect(element(by.id('number-default')).getText()).toBe('3,374.333');
18772                  expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
18773                  expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
18774               });
18775              </file>
18776            </example>
18777          */
18778
18779
18780         numberFilter.$inject = ['$locale'];
18781         function numberFilter($locale) {
18782           var formats = $locale.NUMBER_FORMATS;
18783           return function(number, fractionSize) {
18784
18785             // if null or undefined pass it through
18786             return (number == null)
18787                 ? number
18788                 : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
18789                                fractionSize);
18790           };
18791         }
18792
18793         var DECIMAL_SEP = '.';
18794         function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
18795           if (isObject(number)) return '';
18796
18797           var isNegative = number < 0;
18798           number = Math.abs(number);
18799
18800           var isInfinity = number === Infinity;
18801           if (!isInfinity && !isFinite(number)) return '';
18802
18803           var numStr = number + '',
18804               formatedText = '',
18805               hasExponent = false,
18806               parts = [];
18807
18808           if (isInfinity) formatedText = '\u221e';
18809
18810           if (!isInfinity && numStr.indexOf('e') !== -1) {
18811             var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
18812             if (match && match[2] == '-' && match[3] > fractionSize + 1) {
18813               number = 0;
18814             } else {
18815               formatedText = numStr;
18816               hasExponent = true;
18817             }
18818           }
18819
18820           if (!isInfinity && !hasExponent) {
18821             var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
18822
18823             // determine fractionSize if it is not specified
18824             if (isUndefined(fractionSize)) {
18825               fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
18826             }
18827
18828             // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
18829             // inspired by:
18830             // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
18831             number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
18832
18833             var fraction = ('' + number).split(DECIMAL_SEP);
18834             var whole = fraction[0];
18835             fraction = fraction[1] || '';
18836
18837             var i, pos = 0,
18838                 lgroup = pattern.lgSize,
18839                 group = pattern.gSize;
18840
18841             if (whole.length >= (lgroup + group)) {
18842               pos = whole.length - lgroup;
18843               for (i = 0; i < pos; i++) {
18844                 if ((pos - i) % group === 0 && i !== 0) {
18845                   formatedText += groupSep;
18846                 }
18847                 formatedText += whole.charAt(i);
18848               }
18849             }
18850
18851             for (i = pos; i < whole.length; i++) {
18852               if ((whole.length - i) % lgroup === 0 && i !== 0) {
18853                 formatedText += groupSep;
18854               }
18855               formatedText += whole.charAt(i);
18856             }
18857
18858             // format fraction part.
18859             while (fraction.length < fractionSize) {
18860               fraction += '0';
18861             }
18862
18863             if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
18864           } else {
18865             if (fractionSize > 0 && number < 1) {
18866               formatedText = number.toFixed(fractionSize);
18867               number = parseFloat(formatedText);
18868               formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
18869             }
18870           }
18871
18872           if (number === 0) {
18873             isNegative = false;
18874           }
18875
18876           parts.push(isNegative ? pattern.negPre : pattern.posPre,
18877                      formatedText,
18878                      isNegative ? pattern.negSuf : pattern.posSuf);
18879           return parts.join('');
18880         }
18881
18882         function padNumber(num, digits, trim) {
18883           var neg = '';
18884           if (num < 0) {
18885             neg =  '-';
18886             num = -num;
18887           }
18888           num = '' + num;
18889           while (num.length < digits) num = '0' + num;
18890           if (trim) {
18891             num = num.substr(num.length - digits);
18892           }
18893           return neg + num;
18894         }
18895
18896
18897         function dateGetter(name, size, offset, trim) {
18898           offset = offset || 0;
18899           return function(date) {
18900             var value = date['get' + name]();
18901             if (offset > 0 || value > -offset) {
18902               value += offset;
18903             }
18904             if (value === 0 && offset == -12) value = 12;
18905             return padNumber(value, size, trim);
18906           };
18907         }
18908
18909         function dateStrGetter(name, shortForm) {
18910           return function(date, formats) {
18911             var value = date['get' + name]();
18912             var get = uppercase(shortForm ? ('SHORT' + name) : name);
18913
18914             return formats[get][value];
18915           };
18916         }
18917
18918         function timeZoneGetter(date, formats, offset) {
18919           var zone = -1 * offset;
18920           var paddedZone = (zone >= 0) ? "+" : "";
18921
18922           paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
18923                         padNumber(Math.abs(zone % 60), 2);
18924
18925           return paddedZone;
18926         }
18927
18928         function getFirstThursdayOfYear(year) {
18929             // 0 = index of January
18930             var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
18931             // 4 = index of Thursday (+1 to account for 1st = 5)
18932             // 11 = index of *next* Thursday (+1 account for 1st = 12)
18933             return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
18934         }
18935
18936         function getThursdayThisWeek(datetime) {
18937             return new Date(datetime.getFullYear(), datetime.getMonth(),
18938               // 4 = index of Thursday
18939               datetime.getDate() + (4 - datetime.getDay()));
18940         }
18941
18942         function weekGetter(size) {
18943            return function(date) {
18944               var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
18945                  thisThurs = getThursdayThisWeek(date);
18946
18947               var diff = +thisThurs - +firstThurs,
18948                  result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
18949
18950               return padNumber(result, size);
18951            };
18952         }
18953
18954         function ampmGetter(date, formats) {
18955           return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
18956         }
18957
18958         function eraGetter(date, formats) {
18959           return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
18960         }
18961
18962         function longEraGetter(date, formats) {
18963           return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
18964         }
18965
18966         var DATE_FORMATS = {
18967           yyyy: dateGetter('FullYear', 4),
18968             yy: dateGetter('FullYear', 2, 0, true),
18969              y: dateGetter('FullYear', 1),
18970           MMMM: dateStrGetter('Month'),
18971            MMM: dateStrGetter('Month', true),
18972             MM: dateGetter('Month', 2, 1),
18973              M: dateGetter('Month', 1, 1),
18974             dd: dateGetter('Date', 2),
18975              d: dateGetter('Date', 1),
18976             HH: dateGetter('Hours', 2),
18977              H: dateGetter('Hours', 1),
18978             hh: dateGetter('Hours', 2, -12),
18979              h: dateGetter('Hours', 1, -12),
18980             mm: dateGetter('Minutes', 2),
18981              m: dateGetter('Minutes', 1),
18982             ss: dateGetter('Seconds', 2),
18983              s: dateGetter('Seconds', 1),
18984              // while ISO 8601 requires fractions to be prefixed with `.` or `,`
18985              // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
18986            sss: dateGetter('Milliseconds', 3),
18987           EEEE: dateStrGetter('Day'),
18988            EEE: dateStrGetter('Day', true),
18989              a: ampmGetter,
18990              Z: timeZoneGetter,
18991             ww: weekGetter(2),
18992              w: weekGetter(1),
18993              G: eraGetter,
18994              GG: eraGetter,
18995              GGG: eraGetter,
18996              GGGG: longEraGetter
18997         };
18998
18999         var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
19000             NUMBER_STRING = /^\-?\d+$/;
19001
19002         /**
19003          * @ngdoc filter
19004          * @name date
19005          * @kind function
19006          *
19007          * @description
19008          *   Formats `date` to a string based on the requested `format`.
19009          *
19010          *   `format` string can be composed of the following elements:
19011          *
19012          *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
19013          *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
19014          *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
19015          *   * `'MMMM'`: Month in year (January-December)
19016          *   * `'MMM'`: Month in year (Jan-Dec)
19017          *   * `'MM'`: Month in year, padded (01-12)
19018          *   * `'M'`: Month in year (1-12)
19019          *   * `'dd'`: Day in month, padded (01-31)
19020          *   * `'d'`: Day in month (1-31)
19021          *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
19022          *   * `'EEE'`: Day in Week, (Sun-Sat)
19023          *   * `'HH'`: Hour in day, padded (00-23)
19024          *   * `'H'`: Hour in day (0-23)
19025          *   * `'hh'`: Hour in AM/PM, padded (01-12)
19026          *   * `'h'`: Hour in AM/PM, (1-12)
19027          *   * `'mm'`: Minute in hour, padded (00-59)
19028          *   * `'m'`: Minute in hour (0-59)
19029          *   * `'ss'`: Second in minute, padded (00-59)
19030          *   * `'s'`: Second in minute (0-59)
19031          *   * `'sss'`: Millisecond in second, padded (000-999)
19032          *   * `'a'`: AM/PM marker
19033          *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
19034          *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
19035          *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
19036          *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
19037          *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
19038          *
19039          *   `format` string can also be one of the following predefined
19040          *   {@link guide/i18n localizable formats}:
19041          *
19042          *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
19043          *     (e.g. Sep 3, 2010 12:05:08 PM)
19044          *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
19045          *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
19046          *     (e.g. Friday, September 3, 2010)
19047          *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
19048          *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
19049          *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
19050          *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
19051          *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
19052          *
19053          *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
19054          *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
19055          *   (e.g. `"h 'o''clock'"`).
19056          *
19057          * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
19058          *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
19059          *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
19060          *    specified in the string input, the time is considered to be in the local timezone.
19061          * @param {string=} format Formatting rules (see Description). If not specified,
19062          *    `mediumDate` is used.
19063          * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
19064          *    continental US time zone abbreviations, but for general use, use a time zone offset, for
19065          *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
19066          *    If not specified, the timezone of the browser will be used.
19067          * @returns {string} Formatted string or the input if input is not recognized as date/millis.
19068          *
19069          * @example
19070            <example>
19071              <file name="index.html">
19072                <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
19073                    <span>{{1288323623006 | date:'medium'}}</span><br>
19074                <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
19075                   <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
19076                <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
19077                   <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
19078                <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
19079                   <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
19080              </file>
19081              <file name="protractor.js" type="protractor">
19082                it('should format date', function() {
19083                  expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
19084                     toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
19085                  expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
19086                     toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
19087                  expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
19088                     toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
19089                  expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
19090                     toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
19091                });
19092              </file>
19093            </example>
19094          */
19095         dateFilter.$inject = ['$locale'];
19096         function dateFilter($locale) {
19097
19098
19099           var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
19100                              // 1        2       3         4          5          6          7          8  9     10      11
19101           function jsonStringToDate(string) {
19102             var match;
19103             if (match = string.match(R_ISO8601_STR)) {
19104               var date = new Date(0),
19105                   tzHour = 0,
19106                   tzMin  = 0,
19107                   dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
19108                   timeSetter = match[8] ? date.setUTCHours : date.setHours;
19109
19110               if (match[9]) {
19111                 tzHour = toInt(match[9] + match[10]);
19112                 tzMin = toInt(match[9] + match[11]);
19113               }
19114               dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
19115               var h = toInt(match[4] || 0) - tzHour;
19116               var m = toInt(match[5] || 0) - tzMin;
19117               var s = toInt(match[6] || 0);
19118               var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
19119               timeSetter.call(date, h, m, s, ms);
19120               return date;
19121             }
19122             return string;
19123           }
19124
19125
19126           return function(date, format, timezone) {
19127             var text = '',
19128                 parts = [],
19129                 fn, match;
19130
19131             format = format || 'mediumDate';
19132             format = $locale.DATETIME_FORMATS[format] || format;
19133             if (isString(date)) {
19134               date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
19135             }
19136
19137             if (isNumber(date)) {
19138               date = new Date(date);
19139             }
19140
19141             if (!isDate(date) || !isFinite(date.getTime())) {
19142               return date;
19143             }
19144
19145             while (format) {
19146               match = DATE_FORMATS_SPLIT.exec(format);
19147               if (match) {
19148                 parts = concat(parts, match, 1);
19149                 format = parts.pop();
19150               } else {
19151                 parts.push(format);
19152                 format = null;
19153               }
19154             }
19155
19156             var dateTimezoneOffset = date.getTimezoneOffset();
19157             if (timezone) {
19158               dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
19159               date = convertTimezoneToLocal(date, timezone, true);
19160             }
19161             forEach(parts, function(value) {
19162               fn = DATE_FORMATS[value];
19163               text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
19164                          : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
19165             });
19166
19167             return text;
19168           };
19169         }
19170
19171
19172         /**
19173          * @ngdoc filter
19174          * @name json
19175          * @kind function
19176          *
19177          * @description
19178          *   Allows you to convert a JavaScript object into JSON string.
19179          *
19180          *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
19181          *   the binding is automatically converted to JSON.
19182          *
19183          * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
19184          * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
19185          * @returns {string} JSON string.
19186          *
19187          *
19188          * @example
19189            <example>
19190              <file name="index.html">
19191                <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
19192                <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
19193              </file>
19194              <file name="protractor.js" type="protractor">
19195                it('should jsonify filtered objects', function() {
19196                  expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
19197                  expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
19198                });
19199              </file>
19200            </example>
19201          *
19202          */
19203         function jsonFilter() {
19204           return function(object, spacing) {
19205             if (isUndefined(spacing)) {
19206                 spacing = 2;
19207             }
19208             return toJson(object, spacing);
19209           };
19210         }
19211
19212
19213         /**
19214          * @ngdoc filter
19215          * @name lowercase
19216          * @kind function
19217          * @description
19218          * Converts string to lowercase.
19219          * @see angular.lowercase
19220          */
19221         var lowercaseFilter = valueFn(lowercase);
19222
19223
19224         /**
19225          * @ngdoc filter
19226          * @name uppercase
19227          * @kind function
19228          * @description
19229          * Converts string to uppercase.
19230          * @see angular.uppercase
19231          */
19232         var uppercaseFilter = valueFn(uppercase);
19233
19234         /**
19235          * @ngdoc filter
19236          * @name limitTo
19237          * @kind function
19238          *
19239          * @description
19240          * Creates a new array or string containing only a specified number of elements. The elements
19241          * are taken from either the beginning or the end of the source array, string or number, as specified by
19242          * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
19243          * converted to a string.
19244          *
19245          * @param {Array|string|number} input Source array, string or number to be limited.
19246          * @param {string|number} limit The length of the returned array or string. If the `limit` number
19247          *     is positive, `limit` number of items from the beginning of the source array/string are copied.
19248          *     If the number is negative, `limit` number  of items from the end of the source array/string
19249          *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
19250          *     the input will be returned unchanged.
19251          * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
19252          *     indicates an offset from the end of `input`. Defaults to `0`.
19253          * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
19254          *     had less than `limit` elements.
19255          *
19256          * @example
19257            <example module="limitToExample">
19258              <file name="index.html">
19259                <script>
19260                  angular.module('limitToExample', [])
19261                    .controller('ExampleController', ['$scope', function($scope) {
19262                      $scope.numbers = [1,2,3,4,5,6,7,8,9];
19263                      $scope.letters = "abcdefghi";
19264                      $scope.longNumber = 2345432342;
19265                      $scope.numLimit = 3;
19266                      $scope.letterLimit = 3;
19267                      $scope.longNumberLimit = 3;
19268                    }]);
19269                </script>
19270                <div ng-controller="ExampleController">
19271                  <label>
19272                     Limit {{numbers}} to:
19273                     <input type="number" step="1" ng-model="numLimit">
19274                  </label>
19275                  <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
19276                  <label>
19277                     Limit {{letters}} to:
19278                     <input type="number" step="1" ng-model="letterLimit">
19279                  </label>
19280                  <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
19281                  <label>
19282                     Limit {{longNumber}} to:
19283                     <input type="number" step="1" ng-model="longNumberLimit">
19284                  </label>
19285                  <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
19286                </div>
19287              </file>
19288              <file name="protractor.js" type="protractor">
19289                var numLimitInput = element(by.model('numLimit'));
19290                var letterLimitInput = element(by.model('letterLimit'));
19291                var longNumberLimitInput = element(by.model('longNumberLimit'));
19292                var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
19293                var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
19294                var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
19295
19296                it('should limit the number array to first three items', function() {
19297                  expect(numLimitInput.getAttribute('value')).toBe('3');
19298                  expect(letterLimitInput.getAttribute('value')).toBe('3');
19299                  expect(longNumberLimitInput.getAttribute('value')).toBe('3');
19300                  expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
19301                  expect(limitedLetters.getText()).toEqual('Output letters: abc');
19302                  expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
19303                });
19304
19305                // There is a bug in safari and protractor that doesn't like the minus key
19306                // it('should update the output when -3 is entered', function() {
19307                //   numLimitInput.clear();
19308                //   numLimitInput.sendKeys('-3');
19309                //   letterLimitInput.clear();
19310                //   letterLimitInput.sendKeys('-3');
19311                //   longNumberLimitInput.clear();
19312                //   longNumberLimitInput.sendKeys('-3');
19313                //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
19314                //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
19315                //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
19316                // });
19317
19318                it('should not exceed the maximum size of input array', function() {
19319                  numLimitInput.clear();
19320                  numLimitInput.sendKeys('100');
19321                  letterLimitInput.clear();
19322                  letterLimitInput.sendKeys('100');
19323                  longNumberLimitInput.clear();
19324                  longNumberLimitInput.sendKeys('100');
19325                  expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
19326                  expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
19327                  expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
19328                });
19329              </file>
19330            </example>
19331         */
19332         function limitToFilter() {
19333           return function(input, limit, begin) {
19334             if (Math.abs(Number(limit)) === Infinity) {
19335               limit = Number(limit);
19336             } else {
19337               limit = toInt(limit);
19338             }
19339             if (isNaN(limit)) return input;
19340
19341             if (isNumber(input)) input = input.toString();
19342             if (!isArray(input) && !isString(input)) return input;
19343
19344             begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
19345             begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
19346
19347             if (limit >= 0) {
19348               return input.slice(begin, begin + limit);
19349             } else {
19350               if (begin === 0) {
19351                 return input.slice(limit, input.length);
19352               } else {
19353                 return input.slice(Math.max(0, begin + limit), begin);
19354               }
19355             }
19356           };
19357         }
19358
19359         /**
19360          * @ngdoc filter
19361          * @name orderBy
19362          * @kind function
19363          *
19364          * @description
19365          * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
19366          * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
19367          * as expected, make sure they are actually being saved as numbers and not strings.
19368          *
19369          * @param {Array} array The array to sort.
19370          * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
19371          *    used by the comparator to determine the order of elements.
19372          *
19373          *    Can be one of:
19374          *
19375          *    - `function`: Getter function. The result of this function will be sorted using the
19376          *      `<`, `===`, `>` operator.
19377          *    - `string`: An Angular expression. The result of this expression is used to compare elements
19378          *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
19379          *      3 first characters of a property called `name`). The result of a constant expression
19380          *      is interpreted as a property name to be used in comparisons (for example `"special name"`
19381          *      to sort object by the value of their `special name` property). An expression can be
19382          *      optionally prefixed with `+` or `-` to control ascending or descending sort order
19383          *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
19384          *      element itself is used to compare where sorting.
19385          *    - `Array`: An array of function or string predicates. The first predicate in the array
19386          *      is used for sorting, but when two items are equivalent, the next predicate is used.
19387          *
19388          *    If the predicate is missing or empty then it defaults to `'+'`.
19389          *
19390          * @param {boolean=} reverse Reverse the order of the array.
19391          * @returns {Array} Sorted copy of the source array.
19392          *
19393          *
19394          * @example
19395          * The example below demonstrates a simple ngRepeat, where the data is sorted
19396          * by age in descending order (predicate is set to `'-age'`).
19397          * `reverse` is not set, which means it defaults to `false`.
19398            <example module="orderByExample">
19399              <file name="index.html">
19400                <script>
19401                  angular.module('orderByExample', [])
19402                    .controller('ExampleController', ['$scope', function($scope) {
19403                      $scope.friends =
19404                          [{name:'John', phone:'555-1212', age:10},
19405                           {name:'Mary', phone:'555-9876', age:19},
19406                           {name:'Mike', phone:'555-4321', age:21},
19407                           {name:'Adam', phone:'555-5678', age:35},
19408                           {name:'Julie', phone:'555-8765', age:29}];
19409                    }]);
19410                </script>
19411                <div ng-controller="ExampleController">
19412                  <table class="friend">
19413                    <tr>
19414                      <th>Name</th>
19415                      <th>Phone Number</th>
19416                      <th>Age</th>
19417                    </tr>
19418                    <tr ng-repeat="friend in friends | orderBy:'-age'">
19419                      <td>{{friend.name}}</td>
19420                      <td>{{friend.phone}}</td>
19421                      <td>{{friend.age}}</td>
19422                    </tr>
19423                  </table>
19424                </div>
19425              </file>
19426            </example>
19427          *
19428          * The predicate and reverse parameters can be controlled dynamically through scope properties,
19429          * as shown in the next example.
19430          * @example
19431            <example module="orderByExample">
19432              <file name="index.html">
19433                <script>
19434                  angular.module('orderByExample', [])
19435                    .controller('ExampleController', ['$scope', function($scope) {
19436                      $scope.friends =
19437                          [{name:'John', phone:'555-1212', age:10},
19438                           {name:'Mary', phone:'555-9876', age:19},
19439                           {name:'Mike', phone:'555-4321', age:21},
19440                           {name:'Adam', phone:'555-5678', age:35},
19441                           {name:'Julie', phone:'555-8765', age:29}];
19442                      $scope.predicate = 'age';
19443                      $scope.reverse = true;
19444                      $scope.order = function(predicate) {
19445                        $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
19446                        $scope.predicate = predicate;
19447                      };
19448                    }]);
19449                </script>
19450                <style type="text/css">
19451                  .sortorder:after {
19452                    content: '\25b2';
19453                  }
19454                  .sortorder.reverse:after {
19455                    content: '\25bc';
19456                  }
19457                </style>
19458                <div ng-controller="ExampleController">
19459                  <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
19460                  <hr/>
19461                  [ <a href="" ng-click="predicate=''">unsorted</a> ]
19462                  <table class="friend">
19463                    <tr>
19464                      <th>
19465                        <a href="" ng-click="order('name')">Name</a>
19466                        <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
19467                      </th>
19468                      <th>
19469                        <a href="" ng-click="order('phone')">Phone Number</a>
19470                        <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
19471                      </th>
19472                      <th>
19473                        <a href="" ng-click="order('age')">Age</a>
19474                        <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
19475                      </th>
19476                    </tr>
19477                    <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
19478                      <td>{{friend.name}}</td>
19479                      <td>{{friend.phone}}</td>
19480                      <td>{{friend.age}}</td>
19481                    </tr>
19482                  </table>
19483                </div>
19484              </file>
19485            </example>
19486          *
19487          * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
19488          * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
19489          * desired parameters.
19490          *
19491          * Example:
19492          *
19493          * @example
19494           <example module="orderByExample">
19495             <file name="index.html">
19496               <div ng-controller="ExampleController">
19497                 <table class="friend">
19498                   <tr>
19499                     <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
19500                       (<a href="" ng-click="order('-name',false)">^</a>)</th>
19501                     <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
19502                     <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
19503                   </tr>
19504                   <tr ng-repeat="friend in friends">
19505                     <td>{{friend.name}}</td>
19506                     <td>{{friend.phone}}</td>
19507                     <td>{{friend.age}}</td>
19508                   </tr>
19509                 </table>
19510               </div>
19511             </file>
19512
19513             <file name="script.js">
19514               angular.module('orderByExample', [])
19515                 .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
19516                   var orderBy = $filter('orderBy');
19517                   $scope.friends = [
19518                     { name: 'John',    phone: '555-1212',    age: 10 },
19519                     { name: 'Mary',    phone: '555-9876',    age: 19 },
19520                     { name: 'Mike',    phone: '555-4321',    age: 21 },
19521                     { name: 'Adam',    phone: '555-5678',    age: 35 },
19522                     { name: 'Julie',   phone: '555-8765',    age: 29 }
19523                   ];
19524                   $scope.order = function(predicate, reverse) {
19525                     $scope.friends = orderBy($scope.friends, predicate, reverse);
19526                   };
19527                   $scope.order('-age',false);
19528                 }]);
19529             </file>
19530         </example>
19531          */
19532         orderByFilter.$inject = ['$parse'];
19533         function orderByFilter($parse) {
19534           return function(array, sortPredicate, reverseOrder) {
19535
19536             if (!(isArrayLike(array))) return array;
19537
19538             if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
19539             if (sortPredicate.length === 0) { sortPredicate = ['+']; }
19540
19541             var predicates = processPredicates(sortPredicate, reverseOrder);
19542             // Add a predicate at the end that evaluates to the element index. This makes the
19543             // sort stable as it works as a tie-breaker when all the input predicates cannot
19544             // distinguish between two elements.
19545             predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
19546
19547             // The next three lines are a version of a Swartzian Transform idiom from Perl
19548             // (sometimes called the Decorate-Sort-Undecorate idiom)
19549             // See https://en.wikipedia.org/wiki/Schwartzian_transform
19550             var compareValues = Array.prototype.map.call(array, getComparisonObject);
19551             compareValues.sort(doComparison);
19552             array = compareValues.map(function(item) { return item.value; });
19553
19554             return array;
19555
19556             function getComparisonObject(value, index) {
19557               return {
19558                 value: value,
19559                 predicateValues: predicates.map(function(predicate) {
19560                   return getPredicateValue(predicate.get(value), index);
19561                 })
19562               };
19563             }
19564
19565             function doComparison(v1, v2) {
19566               var result = 0;
19567               for (var index=0, length = predicates.length; index < length; ++index) {
19568                 result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
19569                 if (result) break;
19570               }
19571               return result;
19572             }
19573           };
19574
19575           function processPredicates(sortPredicate, reverseOrder) {
19576             reverseOrder = reverseOrder ? -1 : 1;
19577             return sortPredicate.map(function(predicate) {
19578               var descending = 1, get = identity;
19579
19580               if (isFunction(predicate)) {
19581                 get = predicate;
19582               } else if (isString(predicate)) {
19583                 if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
19584                   descending = predicate.charAt(0) == '-' ? -1 : 1;
19585                   predicate = predicate.substring(1);
19586                 }
19587                 if (predicate !== '') {
19588                   get = $parse(predicate);
19589                   if (get.constant) {
19590                     var key = get();
19591                     get = function(value) { return value[key]; };
19592                   }
19593                 }
19594               }
19595               return { get: get, descending: descending * reverseOrder };
19596             });
19597           }
19598
19599           function isPrimitive(value) {
19600             switch (typeof value) {
19601               case 'number': /* falls through */
19602               case 'boolean': /* falls through */
19603               case 'string':
19604                 return true;
19605               default:
19606                 return false;
19607             }
19608           }
19609
19610           function objectValue(value, index) {
19611             // If `valueOf` is a valid function use that
19612             if (typeof value.valueOf === 'function') {
19613               value = value.valueOf();
19614               if (isPrimitive(value)) return value;
19615             }
19616             // If `toString` is a valid function and not the one from `Object.prototype` use that
19617             if (hasCustomToString(value)) {
19618               value = value.toString();
19619               if (isPrimitive(value)) return value;
19620             }
19621             // We have a basic object so we use the position of the object in the collection
19622             return index;
19623           }
19624
19625           function getPredicateValue(value, index) {
19626             var type = typeof value;
19627             if (value === null) {
19628               type = 'string';
19629               value = 'null';
19630             } else if (type === 'string') {
19631               value = value.toLowerCase();
19632             } else if (type === 'object') {
19633               value = objectValue(value, index);
19634             }
19635             return { value: value, type: type };
19636           }
19637
19638           function compare(v1, v2) {
19639             var result = 0;
19640             if (v1.type === v2.type) {
19641               if (v1.value !== v2.value) {
19642                 result = v1.value < v2.value ? -1 : 1;
19643               }
19644             } else {
19645               result = v1.type < v2.type ? -1 : 1;
19646             }
19647             return result;
19648           }
19649         }
19650
19651         function ngDirective(directive) {
19652           if (isFunction(directive)) {
19653             directive = {
19654               link: directive
19655             };
19656           }
19657           directive.restrict = directive.restrict || 'AC';
19658           return valueFn(directive);
19659         }
19660
19661         /**
19662          * @ngdoc directive
19663          * @name a
19664          * @restrict E
19665          *
19666          * @description
19667          * Modifies the default behavior of the html A tag so that the default action is prevented when
19668          * the href attribute is empty.
19669          *
19670          * This change permits the easy creation of action links with the `ngClick` directive
19671          * without changing the location or causing page reloads, e.g.:
19672          * `<a href="" ng-click="list.addItem()">Add Item</a>`
19673          */
19674         var htmlAnchorDirective = valueFn({
19675           restrict: 'E',
19676           compile: function(element, attr) {
19677             if (!attr.href && !attr.xlinkHref) {
19678               return function(scope, element) {
19679                 // If the linked element is not an anchor tag anymore, do nothing
19680                 if (element[0].nodeName.toLowerCase() !== 'a') return;
19681
19682                 // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
19683                 var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
19684                            'xlink:href' : 'href';
19685                 element.on('click', function(event) {
19686                   // if we have no href url, then don't navigate anywhere.
19687                   if (!element.attr(href)) {
19688                     event.preventDefault();
19689                   }
19690                 });
19691               };
19692             }
19693           }
19694         });
19695
19696         /**
19697          * @ngdoc directive
19698          * @name ngHref
19699          * @restrict A
19700          * @priority 99
19701          *
19702          * @description
19703          * Using Angular markup like `{{hash}}` in an href attribute will
19704          * make the link go to the wrong URL if the user clicks it before
19705          * Angular has a chance to replace the `{{hash}}` markup with its
19706          * value. Until Angular replaces the markup the link will be broken
19707          * and will most likely return a 404 error. The `ngHref` directive
19708          * solves this problem.
19709          *
19710          * The wrong way to write it:
19711          * ```html
19712          * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19713          * ```
19714          *
19715          * The correct way to write it:
19716          * ```html
19717          * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19718          * ```
19719          *
19720          * @element A
19721          * @param {template} ngHref any string which can contain `{{}}` markup.
19722          *
19723          * @example
19724          * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
19725          * in links and their different behaviors:
19726             <example>
19727               <file name="index.html">
19728                 <input ng-model="value" /><br />
19729                 <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
19730                 <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
19731                 <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
19732                 <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
19733                 <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
19734                 <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
19735               </file>
19736               <file name="protractor.js" type="protractor">
19737                 it('should execute ng-click but not reload when href without value', function() {
19738                   element(by.id('link-1')).click();
19739                   expect(element(by.model('value')).getAttribute('value')).toEqual('1');
19740                   expect(element(by.id('link-1')).getAttribute('href')).toBe('');
19741                 });
19742
19743                 it('should execute ng-click but not reload when href empty string', function() {
19744                   element(by.id('link-2')).click();
19745                   expect(element(by.model('value')).getAttribute('value')).toEqual('2');
19746                   expect(element(by.id('link-2')).getAttribute('href')).toBe('');
19747                 });
19748
19749                 it('should execute ng-click and change url when ng-href specified', function() {
19750                   expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
19751
19752                   element(by.id('link-3')).click();
19753
19754                   // At this point, we navigate away from an Angular page, so we need
19755                   // to use browser.driver to get the base webdriver.
19756
19757                   browser.wait(function() {
19758                     return browser.driver.getCurrentUrl().then(function(url) {
19759                       return url.match(/\/123$/);
19760                     });
19761                   }, 5000, 'page should navigate to /123');
19762                 });
19763
19764                 it('should execute ng-click but not reload when href empty string and name specified', function() {
19765                   element(by.id('link-4')).click();
19766                   expect(element(by.model('value')).getAttribute('value')).toEqual('4');
19767                   expect(element(by.id('link-4')).getAttribute('href')).toBe('');
19768                 });
19769
19770                 it('should execute ng-click but not reload when no href but name specified', function() {
19771                   element(by.id('link-5')).click();
19772                   expect(element(by.model('value')).getAttribute('value')).toEqual('5');
19773                   expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
19774                 });
19775
19776                 it('should only change url when only ng-href', function() {
19777                   element(by.model('value')).clear();
19778                   element(by.model('value')).sendKeys('6');
19779                   expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
19780
19781                   element(by.id('link-6')).click();
19782
19783                   // At this point, we navigate away from an Angular page, so we need
19784                   // to use browser.driver to get the base webdriver.
19785                   browser.wait(function() {
19786                     return browser.driver.getCurrentUrl().then(function(url) {
19787                       return url.match(/\/6$/);
19788                     });
19789                   }, 5000, 'page should navigate to /6');
19790                 });
19791               </file>
19792             </example>
19793          */
19794
19795         /**
19796          * @ngdoc directive
19797          * @name ngSrc
19798          * @restrict A
19799          * @priority 99
19800          *
19801          * @description
19802          * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
19803          * work right: The browser will fetch from the URL with the literal
19804          * text `{{hash}}` until Angular replaces the expression inside
19805          * `{{hash}}`. The `ngSrc` directive solves this problem.
19806          *
19807          * The buggy way to write it:
19808          * ```html
19809          * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
19810          * ```
19811          *
19812          * The correct way to write it:
19813          * ```html
19814          * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
19815          * ```
19816          *
19817          * @element IMG
19818          * @param {template} ngSrc any string which can contain `{{}}` markup.
19819          */
19820
19821         /**
19822          * @ngdoc directive
19823          * @name ngSrcset
19824          * @restrict A
19825          * @priority 99
19826          *
19827          * @description
19828          * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
19829          * work right: The browser will fetch from the URL with the literal
19830          * text `{{hash}}` until Angular replaces the expression inside
19831          * `{{hash}}`. The `ngSrcset` directive solves this problem.
19832          *
19833          * The buggy way to write it:
19834          * ```html
19835          * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
19836          * ```
19837          *
19838          * The correct way to write it:
19839          * ```html
19840          * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
19841          * ```
19842          *
19843          * @element IMG
19844          * @param {template} ngSrcset any string which can contain `{{}}` markup.
19845          */
19846
19847         /**
19848          * @ngdoc directive
19849          * @name ngDisabled
19850          * @restrict A
19851          * @priority 100
19852          *
19853          * @description
19854          *
19855          * This directive sets the `disabled` attribute on the element if the
19856          * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
19857          *
19858          * A special directive is necessary because we cannot use interpolation inside the `disabled`
19859          * attribute.  The following example would make the button enabled on Chrome/Firefox
19860          * but not on older IEs:
19861          *
19862          * ```html
19863          * <!-- See below for an example of ng-disabled being used correctly -->
19864          * <div ng-init="isDisabled = false">
19865          *  <button disabled="{{isDisabled}}">Disabled</button>
19866          * </div>
19867          * ```
19868          *
19869          * This is because the HTML specification does not require browsers to preserve the values of
19870          * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
19871          * If we put an Angular interpolation expression into such an attribute then the
19872          * binding information would be lost when the browser removes the attribute.
19873          *
19874          * @example
19875             <example>
19876               <file name="index.html">
19877                 <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
19878                 <button ng-model="button" ng-disabled="checked">Button</button>
19879               </file>
19880               <file name="protractor.js" type="protractor">
19881                 it('should toggle button', function() {
19882                   expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
19883                   element(by.model('checked')).click();
19884                   expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
19885                 });
19886               </file>
19887             </example>
19888          *
19889          * @element INPUT
19890          * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
19891          *     then the `disabled` attribute will be set on the element
19892          */
19893
19894
19895         /**
19896          * @ngdoc directive
19897          * @name ngChecked
19898          * @restrict A
19899          * @priority 100
19900          *
19901          * @description
19902          * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
19903          *
19904          * Note that this directive should not be used together with {@link ngModel `ngModel`},
19905          * as this can lead to unexpected behavior.
19906          *
19907          * ### Why do we need `ngChecked`?
19908          *
19909          * The HTML specification does not require browsers to preserve the values of boolean attributes
19910          * such as checked. (Their presence means true and their absence means false.)
19911          * If we put an Angular interpolation expression into such an attribute then the
19912          * binding information would be lost when the browser removes the attribute.
19913          * The `ngChecked` directive solves this problem for the `checked` attribute.
19914          * This complementary directive is not removed by the browser and so provides
19915          * a permanent reliable place to store the binding information.
19916          * @example
19917             <example>
19918               <file name="index.html">
19919                 <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
19920                 <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
19921               </file>
19922               <file name="protractor.js" type="protractor">
19923                 it('should check both checkBoxes', function() {
19924                   expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
19925                   element(by.model('master')).click();
19926                   expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
19927                 });
19928               </file>
19929             </example>
19930          *
19931          * @element INPUT
19932          * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
19933          *     then the `checked` attribute will be set on the element
19934          */
19935
19936
19937         /**
19938          * @ngdoc directive
19939          * @name ngReadonly
19940          * @restrict A
19941          * @priority 100
19942          *
19943          * @description
19944          * The HTML specification does not require browsers to preserve the values of boolean attributes
19945          * such as readonly. (Their presence means true and their absence means false.)
19946          * If we put an Angular interpolation expression into such an attribute then the
19947          * binding information would be lost when the browser removes the attribute.
19948          * The `ngReadonly` directive solves this problem for the `readonly` attribute.
19949          * This complementary directive is not removed by the browser and so provides
19950          * a permanent reliable place to store the binding information.
19951          * @example
19952             <example>
19953               <file name="index.html">
19954                 <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
19955                 <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
19956               </file>
19957               <file name="protractor.js" type="protractor">
19958                 it('should toggle readonly attr', function() {
19959                   expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
19960                   element(by.model('checked')).click();
19961                   expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
19962                 });
19963               </file>
19964             </example>
19965          *
19966          * @element INPUT
19967          * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
19968          *     then special attribute "readonly" will be set on the element
19969          */
19970
19971
19972         /**
19973          * @ngdoc directive
19974          * @name ngSelected
19975          * @restrict A
19976          * @priority 100
19977          *
19978          * @description
19979          * The HTML specification does not require browsers to preserve the values of boolean attributes
19980          * such as selected. (Their presence means true and their absence means false.)
19981          * If we put an Angular interpolation expression into such an attribute then the
19982          * binding information would be lost when the browser removes the attribute.
19983          * The `ngSelected` directive solves this problem for the `selected` attribute.
19984          * This complementary directive is not removed by the browser and so provides
19985          * a permanent reliable place to store the binding information.
19986          *
19987          * @example
19988             <example>
19989               <file name="index.html">
19990                 <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
19991                 <select aria-label="ngSelected demo">
19992                   <option>Hello!</option>
19993                   <option id="greet" ng-selected="selected">Greetings!</option>
19994                 </select>
19995               </file>
19996               <file name="protractor.js" type="protractor">
19997                 it('should select Greetings!', function() {
19998                   expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
19999                   element(by.model('selected')).click();
20000                   expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
20001                 });
20002               </file>
20003             </example>
20004          *
20005          * @element OPTION
20006          * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
20007          *     then special attribute "selected" will be set on the element
20008          */
20009
20010         /**
20011          * @ngdoc directive
20012          * @name ngOpen
20013          * @restrict A
20014          * @priority 100
20015          *
20016          * @description
20017          * The HTML specification does not require browsers to preserve the values of boolean attributes
20018          * such as open. (Their presence means true and their absence means false.)
20019          * If we put an Angular interpolation expression into such an attribute then the
20020          * binding information would be lost when the browser removes the attribute.
20021          * The `ngOpen` directive solves this problem for the `open` attribute.
20022          * This complementary directive is not removed by the browser and so provides
20023          * a permanent reliable place to store the binding information.
20024          * @example
20025              <example>
20026                <file name="index.html">
20027                  <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
20028                  <details id="details" ng-open="open">
20029                     <summary>Show/Hide me</summary>
20030                  </details>
20031                </file>
20032                <file name="protractor.js" type="protractor">
20033                  it('should toggle open', function() {
20034                    expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
20035                    element(by.model('open')).click();
20036                    expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
20037                  });
20038                </file>
20039              </example>
20040          *
20041          * @element DETAILS
20042          * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
20043          *     then special attribute "open" will be set on the element
20044          */
20045
20046         var ngAttributeAliasDirectives = {};
20047
20048         // boolean attrs are evaluated
20049         forEach(BOOLEAN_ATTR, function(propName, attrName) {
20050           // binding to multiple is not supported
20051           if (propName == "multiple") return;
20052
20053           function defaultLinkFn(scope, element, attr) {
20054             scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
20055               attr.$set(attrName, !!value);
20056             });
20057           }
20058
20059           var normalized = directiveNormalize('ng-' + attrName);
20060           var linkFn = defaultLinkFn;
20061
20062           if (propName === 'checked') {
20063             linkFn = function(scope, element, attr) {
20064               // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
20065               if (attr.ngModel !== attr[normalized]) {
20066                 defaultLinkFn(scope, element, attr);
20067               }
20068             };
20069           }
20070
20071           ngAttributeAliasDirectives[normalized] = function() {
20072             return {
20073               restrict: 'A',
20074               priority: 100,
20075               link: linkFn
20076             };
20077           };
20078         });
20079
20080         // aliased input attrs are evaluated
20081         forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
20082           ngAttributeAliasDirectives[ngAttr] = function() {
20083             return {
20084               priority: 100,
20085               link: function(scope, element, attr) {
20086                 //special case ngPattern when a literal regular expression value
20087                 //is used as the expression (this way we don't have to watch anything).
20088                 if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
20089                   var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
20090                   if (match) {
20091                     attr.$set("ngPattern", new RegExp(match[1], match[2]));
20092                     return;
20093                   }
20094                 }
20095
20096                 scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
20097                   attr.$set(ngAttr, value);
20098                 });
20099               }
20100             };
20101           };
20102         });
20103
20104         // ng-src, ng-srcset, ng-href are interpolated
20105         forEach(['src', 'srcset', 'href'], function(attrName) {
20106           var normalized = directiveNormalize('ng-' + attrName);
20107           ngAttributeAliasDirectives[normalized] = function() {
20108             return {
20109               priority: 99, // it needs to run after the attributes are interpolated
20110               link: function(scope, element, attr) {
20111                 var propName = attrName,
20112                     name = attrName;
20113
20114                 if (attrName === 'href' &&
20115                     toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
20116                   name = 'xlinkHref';
20117                   attr.$attr[name] = 'xlink:href';
20118                   propName = null;
20119                 }
20120
20121                 attr.$observe(normalized, function(value) {
20122                   if (!value) {
20123                     if (attrName === 'href') {
20124                       attr.$set(name, null);
20125                     }
20126                     return;
20127                   }
20128
20129                   attr.$set(name, value);
20130
20131                   // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
20132                   // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
20133                   // to set the property as well to achieve the desired effect.
20134                   // we use attr[attrName] value since $set can sanitize the url.
20135                   if (msie && propName) element.prop(propName, attr[name]);
20136                 });
20137               }
20138             };
20139           };
20140         });
20141
20142         /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
20143          */
20144         var nullFormCtrl = {
20145           $addControl: noop,
20146           $$renameControl: nullFormRenameControl,
20147           $removeControl: noop,
20148           $setValidity: noop,
20149           $setDirty: noop,
20150           $setPristine: noop,
20151           $setSubmitted: noop
20152         },
20153         SUBMITTED_CLASS = 'ng-submitted';
20154
20155         function nullFormRenameControl(control, name) {
20156           control.$name = name;
20157         }
20158
20159         /**
20160          * @ngdoc type
20161          * @name form.FormController
20162          *
20163          * @property {boolean} $pristine True if user has not interacted with the form yet.
20164          * @property {boolean} $dirty True if user has already interacted with the form.
20165          * @property {boolean} $valid True if all of the containing forms and controls are valid.
20166          * @property {boolean} $invalid True if at least one containing control or form is invalid.
20167          * @property {boolean} $pending True if at least one containing control or form is pending.
20168          * @property {boolean} $submitted True if user has submitted the form even if its invalid.
20169          *
20170          * @property {Object} $error Is an object hash, containing references to controls or
20171          *  forms with failing validators, where:
20172          *
20173          *  - keys are validation tokens (error names),
20174          *  - values are arrays of controls or forms that have a failing validator for given error name.
20175          *
20176          *  Built-in validation tokens:
20177          *
20178          *  - `email`
20179          *  - `max`
20180          *  - `maxlength`
20181          *  - `min`
20182          *  - `minlength`
20183          *  - `number`
20184          *  - `pattern`
20185          *  - `required`
20186          *  - `url`
20187          *  - `date`
20188          *  - `datetimelocal`
20189          *  - `time`
20190          *  - `week`
20191          *  - `month`
20192          *
20193          * @description
20194          * `FormController` keeps track of all its controls and nested forms as well as the state of them,
20195          * such as being valid/invalid or dirty/pristine.
20196          *
20197          * Each {@link ng.directive:form form} directive creates an instance
20198          * of `FormController`.
20199          *
20200          */
20201         //asks for $scope to fool the BC controller module
20202         FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
20203         function FormController(element, attrs, $scope, $animate, $interpolate) {
20204           var form = this,
20205               controls = [];
20206
20207           // init state
20208           form.$error = {};
20209           form.$$success = {};
20210           form.$pending = undefined;
20211           form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
20212           form.$dirty = false;
20213           form.$pristine = true;
20214           form.$valid = true;
20215           form.$invalid = false;
20216           form.$submitted = false;
20217           form.$$parentForm = nullFormCtrl;
20218
20219           /**
20220            * @ngdoc method
20221            * @name form.FormController#$rollbackViewValue
20222            *
20223            * @description
20224            * Rollback all form controls pending updates to the `$modelValue`.
20225            *
20226            * Updates may be pending by a debounced event or because the input is waiting for a some future
20227            * event defined in `ng-model-options`. This method is typically needed by the reset button of
20228            * a form that uses `ng-model-options` to pend updates.
20229            */
20230           form.$rollbackViewValue = function() {
20231             forEach(controls, function(control) {
20232               control.$rollbackViewValue();
20233             });
20234           };
20235
20236           /**
20237            * @ngdoc method
20238            * @name form.FormController#$commitViewValue
20239            *
20240            * @description
20241            * Commit all form controls pending updates to the `$modelValue`.
20242            *
20243            * Updates may be pending by a debounced event or because the input is waiting for a some future
20244            * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
20245            * usually handles calling this in response to input events.
20246            */
20247           form.$commitViewValue = function() {
20248             forEach(controls, function(control) {
20249               control.$commitViewValue();
20250             });
20251           };
20252
20253           /**
20254            * @ngdoc method
20255            * @name form.FormController#$addControl
20256            * @param {object} control control object, either a {@link form.FormController} or an
20257            * {@link ngModel.NgModelController}
20258            *
20259            * @description
20260            * Register a control with the form. Input elements using ngModelController do this automatically
20261            * when they are linked.
20262            *
20263            * Note that the current state of the control will not be reflected on the new parent form. This
20264            * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
20265            * state.
20266            *
20267            * However, if the method is used programmatically, for example by adding dynamically created controls,
20268            * or controls that have been previously removed without destroying their corresponding DOM element,
20269            * it's the developers responsiblity to make sure the current state propagates to the parent form.
20270            *
20271            * For example, if an input control is added that is already `$dirty` and has `$error` properties,
20272            * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
20273            */
20274           form.$addControl = function(control) {
20275             // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
20276             // and not added to the scope.  Now we throw an error.
20277             assertNotHasOwnProperty(control.$name, 'input');
20278             controls.push(control);
20279
20280             if (control.$name) {
20281               form[control.$name] = control;
20282             }
20283
20284             control.$$parentForm = form;
20285           };
20286
20287           // Private API: rename a form control
20288           form.$$renameControl = function(control, newName) {
20289             var oldName = control.$name;
20290
20291             if (form[oldName] === control) {
20292               delete form[oldName];
20293             }
20294             form[newName] = control;
20295             control.$name = newName;
20296           };
20297
20298           /**
20299            * @ngdoc method
20300            * @name form.FormController#$removeControl
20301            * @param {object} control control object, either a {@link form.FormController} or an
20302            * {@link ngModel.NgModelController}
20303            *
20304            * @description
20305            * Deregister a control from the form.
20306            *
20307            * Input elements using ngModelController do this automatically when they are destroyed.
20308            *
20309            * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
20310            * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
20311            * different from case to case. For example, removing the only `$dirty` control from a form may or
20312            * may not mean that the form is still `$dirty`.
20313            */
20314           form.$removeControl = function(control) {
20315             if (control.$name && form[control.$name] === control) {
20316               delete form[control.$name];
20317             }
20318             forEach(form.$pending, function(value, name) {
20319               form.$setValidity(name, null, control);
20320             });
20321             forEach(form.$error, function(value, name) {
20322               form.$setValidity(name, null, control);
20323             });
20324             forEach(form.$$success, function(value, name) {
20325               form.$setValidity(name, null, control);
20326             });
20327
20328             arrayRemove(controls, control);
20329             control.$$parentForm = nullFormCtrl;
20330           };
20331
20332
20333           /**
20334            * @ngdoc method
20335            * @name form.FormController#$setValidity
20336            *
20337            * @description
20338            * Sets the validity of a form control.
20339            *
20340            * This method will also propagate to parent forms.
20341            */
20342           addSetValidityMethod({
20343             ctrl: this,
20344             $element: element,
20345             set: function(object, property, controller) {
20346               var list = object[property];
20347               if (!list) {
20348                 object[property] = [controller];
20349               } else {
20350                 var index = list.indexOf(controller);
20351                 if (index === -1) {
20352                   list.push(controller);
20353                 }
20354               }
20355             },
20356             unset: function(object, property, controller) {
20357               var list = object[property];
20358               if (!list) {
20359                 return;
20360               }
20361               arrayRemove(list, controller);
20362               if (list.length === 0) {
20363                 delete object[property];
20364               }
20365             },
20366             $animate: $animate
20367           });
20368
20369           /**
20370            * @ngdoc method
20371            * @name form.FormController#$setDirty
20372            *
20373            * @description
20374            * Sets the form to a dirty state.
20375            *
20376            * This method can be called to add the 'ng-dirty' class and set the form to a dirty
20377            * state (ng-dirty class). This method will also propagate to parent forms.
20378            */
20379           form.$setDirty = function() {
20380             $animate.removeClass(element, PRISTINE_CLASS);
20381             $animate.addClass(element, DIRTY_CLASS);
20382             form.$dirty = true;
20383             form.$pristine = false;
20384             form.$$parentForm.$setDirty();
20385           };
20386
20387           /**
20388            * @ngdoc method
20389            * @name form.FormController#$setPristine
20390            *
20391            * @description
20392            * Sets the form to its pristine state.
20393            *
20394            * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
20395            * state (ng-pristine class). This method will also propagate to all the controls contained
20396            * in this form.
20397            *
20398            * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
20399            * saving or resetting it.
20400            */
20401           form.$setPristine = function() {
20402             $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
20403             form.$dirty = false;
20404             form.$pristine = true;
20405             form.$submitted = false;
20406             forEach(controls, function(control) {
20407               control.$setPristine();
20408             });
20409           };
20410
20411           /**
20412            * @ngdoc method
20413            * @name form.FormController#$setUntouched
20414            *
20415            * @description
20416            * Sets the form to its untouched state.
20417            *
20418            * This method can be called to remove the 'ng-touched' class and set the form controls to their
20419            * untouched state (ng-untouched class).
20420            *
20421            * Setting a form controls back to their untouched state is often useful when setting the form
20422            * back to its pristine state.
20423            */
20424           form.$setUntouched = function() {
20425             forEach(controls, function(control) {
20426               control.$setUntouched();
20427             });
20428           };
20429
20430           /**
20431            * @ngdoc method
20432            * @name form.FormController#$setSubmitted
20433            *
20434            * @description
20435            * Sets the form to its submitted state.
20436            */
20437           form.$setSubmitted = function() {
20438             $animate.addClass(element, SUBMITTED_CLASS);
20439             form.$submitted = true;
20440             form.$$parentForm.$setSubmitted();
20441           };
20442         }
20443
20444         /**
20445          * @ngdoc directive
20446          * @name ngForm
20447          * @restrict EAC
20448          *
20449          * @description
20450          * Nestable alias of {@link ng.directive:form `form`} directive. HTML
20451          * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
20452          * sub-group of controls needs to be determined.
20453          *
20454          * Note: the purpose of `ngForm` is to group controls,
20455          * but not to be a replacement for the `<form>` tag with all of its capabilities
20456          * (e.g. posting to the server, ...).
20457          *
20458          * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
20459          *                       related scope, under this name.
20460          *
20461          */
20462
20463          /**
20464          * @ngdoc directive
20465          * @name form
20466          * @restrict E
20467          *
20468          * @description
20469          * Directive that instantiates
20470          * {@link form.FormController FormController}.
20471          *
20472          * If the `name` attribute is specified, the form controller is published onto the current scope under
20473          * this name.
20474          *
20475          * # Alias: {@link ng.directive:ngForm `ngForm`}
20476          *
20477          * In Angular, forms can be nested. This means that the outer form is valid when all of the child
20478          * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
20479          * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
20480          * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
20481          * using Angular validation directives in forms that are dynamically generated using the
20482          * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
20483          * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
20484          * `ngForm` directive and nest these in an outer `form` element.
20485          *
20486          *
20487          * # CSS classes
20488          *  - `ng-valid` is set if the form is valid.
20489          *  - `ng-invalid` is set if the form is invalid.
20490          *  - `ng-pending` is set if the form is pending.
20491          *  - `ng-pristine` is set if the form is pristine.
20492          *  - `ng-dirty` is set if the form is dirty.
20493          *  - `ng-submitted` is set if the form was submitted.
20494          *
20495          * Keep in mind that ngAnimate can detect each of these classes when added and removed.
20496          *
20497          *
20498          * # Submitting a form and preventing the default action
20499          *
20500          * Since the role of forms in client-side Angular applications is different than in classical
20501          * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
20502          * page reload that sends the data to the server. Instead some javascript logic should be triggered
20503          * to handle the form submission in an application-specific way.
20504          *
20505          * For this reason, Angular prevents the default action (form submission to the server) unless the
20506          * `<form>` element has an `action` attribute specified.
20507          *
20508          * You can use one of the following two ways to specify what javascript method should be called when
20509          * a form is submitted:
20510          *
20511          * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
20512          * - {@link ng.directive:ngClick ngClick} directive on the first
20513           *  button or input field of type submit (input[type=submit])
20514          *
20515          * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
20516          * or {@link ng.directive:ngClick ngClick} directives.
20517          * This is because of the following form submission rules in the HTML specification:
20518          *
20519          * - If a form has only one input field then hitting enter in this field triggers form submit
20520          * (`ngSubmit`)
20521          * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
20522          * doesn't trigger submit
20523          * - if a form has one or more input fields and one or more buttons or input[type=submit] then
20524          * hitting enter in any of the input fields will trigger the click handler on the *first* button or
20525          * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
20526          *
20527          * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
20528          * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
20529          * to have access to the updated model.
20530          *
20531          * ## Animation Hooks
20532          *
20533          * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
20534          * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
20535          * other validations that are performed within the form. Animations in ngForm are similar to how
20536          * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
20537          * as JS animations.
20538          *
20539          * The following example shows a simple way to utilize CSS transitions to style a form element
20540          * that has been rendered as invalid after it has been validated:
20541          *
20542          * <pre>
20543          * //be sure to include ngAnimate as a module to hook into more
20544          * //advanced animations
20545          * .my-form {
20546          *   transition:0.5s linear all;
20547          *   background: white;
20548          * }
20549          * .my-form.ng-invalid {
20550          *   background: red;
20551          *   color:white;
20552          * }
20553          * </pre>
20554          *
20555          * @example
20556             <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
20557               <file name="index.html">
20558                <script>
20559                  angular.module('formExample', [])
20560                    .controller('FormController', ['$scope', function($scope) {
20561                      $scope.userType = 'guest';
20562                    }]);
20563                </script>
20564                <style>
20565                 .my-form {
20566                   transition:all linear 0.5s;
20567                   background: transparent;
20568                 }
20569                 .my-form.ng-invalid {
20570                   background: red;
20571                 }
20572                </style>
20573                <form name="myForm" ng-controller="FormController" class="my-form">
20574                  userType: <input name="input" ng-model="userType" required>
20575                  <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
20576                  <code>userType = {{userType}}</code><br>
20577                  <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
20578                  <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
20579                  <code>myForm.$valid = {{myForm.$valid}}</code><br>
20580                  <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
20581                 </form>
20582               </file>
20583               <file name="protractor.js" type="protractor">
20584                 it('should initialize to model', function() {
20585                   var userType = element(by.binding('userType'));
20586                   var valid = element(by.binding('myForm.input.$valid'));
20587
20588                   expect(userType.getText()).toContain('guest');
20589                   expect(valid.getText()).toContain('true');
20590                 });
20591
20592                 it('should be invalid if empty', function() {
20593                   var userType = element(by.binding('userType'));
20594                   var valid = element(by.binding('myForm.input.$valid'));
20595                   var userInput = element(by.model('userType'));
20596
20597                   userInput.clear();
20598                   userInput.sendKeys('');
20599
20600                   expect(userType.getText()).toEqual('userType =');
20601                   expect(valid.getText()).toContain('false');
20602                 });
20603               </file>
20604             </example>
20605          *
20606          * @param {string=} name Name of the form. If specified, the form controller will be published into
20607          *                       related scope, under this name.
20608          */
20609         var formDirectiveFactory = function(isNgForm) {
20610           return ['$timeout', '$parse', function($timeout, $parse) {
20611             var formDirective = {
20612               name: 'form',
20613               restrict: isNgForm ? 'EAC' : 'E',
20614               require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
20615               controller: FormController,
20616               compile: function ngFormCompile(formElement, attr) {
20617                 // Setup initial state of the control
20618                 formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
20619
20620                 var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
20621
20622                 return {
20623                   pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
20624                     var controller = ctrls[0];
20625
20626                     // if `action` attr is not present on the form, prevent the default action (submission)
20627                     if (!('action' in attr)) {
20628                       // we can't use jq events because if a form is destroyed during submission the default
20629                       // action is not prevented. see #1238
20630                       //
20631                       // IE 9 is not affected because it doesn't fire a submit event and try to do a full
20632                       // page reload if the form was destroyed by submission of the form via a click handler
20633                       // on a button in the form. Looks like an IE9 specific bug.
20634                       var handleFormSubmission = function(event) {
20635                         scope.$apply(function() {
20636                           controller.$commitViewValue();
20637                           controller.$setSubmitted();
20638                         });
20639
20640                         event.preventDefault();
20641                       };
20642
20643                       addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20644
20645                       // unregister the preventDefault listener so that we don't not leak memory but in a
20646                       // way that will achieve the prevention of the default action.
20647                       formElement.on('$destroy', function() {
20648                         $timeout(function() {
20649                           removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20650                         }, 0, false);
20651                       });
20652                     }
20653
20654                     var parentFormCtrl = ctrls[1] || controller.$$parentForm;
20655                     parentFormCtrl.$addControl(controller);
20656
20657                     var setter = nameAttr ? getSetter(controller.$name) : noop;
20658
20659                     if (nameAttr) {
20660                       setter(scope, controller);
20661                       attr.$observe(nameAttr, function(newValue) {
20662                         if (controller.$name === newValue) return;
20663                         setter(scope, undefined);
20664                         controller.$$parentForm.$$renameControl(controller, newValue);
20665                         setter = getSetter(controller.$name);
20666                         setter(scope, controller);
20667                       });
20668                     }
20669                     formElement.on('$destroy', function() {
20670                       controller.$$parentForm.$removeControl(controller);
20671                       setter(scope, undefined);
20672                       extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
20673                     });
20674                   }
20675                 };
20676               }
20677             };
20678
20679             return formDirective;
20680
20681             function getSetter(expression) {
20682               if (expression === '') {
20683                 //create an assignable expression, so forms with an empty name can be renamed later
20684                 return $parse('this[""]').assign;
20685               }
20686               return $parse(expression).assign || noop;
20687             }
20688           }];
20689         };
20690
20691         var formDirective = formDirectiveFactory();
20692         var ngFormDirective = formDirectiveFactory(true);
20693
20694         /* global VALID_CLASS: false,
20695           INVALID_CLASS: false,
20696           PRISTINE_CLASS: false,
20697           DIRTY_CLASS: false,
20698           UNTOUCHED_CLASS: false,
20699           TOUCHED_CLASS: false,
20700           ngModelMinErr: false,
20701         */
20702
20703         // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
20704         var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
20705         // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
20706         var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/;
20707         var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
20708         var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
20709         var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
20710         var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20711         var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
20712         var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
20713         var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20714
20715         var inputType = {
20716
20717           /**
20718            * @ngdoc input
20719            * @name input[text]
20720            *
20721            * @description
20722            * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
20723            *
20724            *
20725            * @param {string} ngModel Assignable angular expression to data-bind to.
20726            * @param {string=} name Property name of the form under which the control is published.
20727            * @param {string=} required Adds `required` validation error key if the value is not entered.
20728            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20729            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20730            *    `required` when you want to data-bind to the `required` attribute.
20731            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20732            *    minlength.
20733            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20734            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
20735            *    any length.
20736            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
20737            *    that contains the regular expression body that will be converted to a regular expression
20738            *    as in the ngPattern directive.
20739            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
20740            *    a RegExp found by evaluating the Angular expression given in the attribute value.
20741            *    If the expression evaluates to a RegExp object, then this is used directly.
20742            *    If the expression evaluates to a string, then it will be converted to a RegExp
20743            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
20744            *    `new RegExp('^abc$')`.<br />
20745            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
20746            *    start at the index of the last search's match, thus not taking the whole input value into
20747            *    account.
20748            * @param {string=} ngChange Angular expression to be executed when input changes due to user
20749            *    interaction with the input element.
20750            * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20751            *    This parameter is ignored for input[type=password] controls, which will never trim the
20752            *    input.
20753            *
20754            * @example
20755               <example name="text-input-directive" module="textInputExample">
20756                 <file name="index.html">
20757                  <script>
20758                    angular.module('textInputExample', [])
20759                      .controller('ExampleController', ['$scope', function($scope) {
20760                        $scope.example = {
20761                          text: 'guest',
20762                          word: /^\s*\w*\s*$/
20763                        };
20764                      }]);
20765                  </script>
20766                  <form name="myForm" ng-controller="ExampleController">
20767                    <label>Single word:
20768                      <input type="text" name="input" ng-model="example.text"
20769                             ng-pattern="example.word" required ng-trim="false">
20770                    </label>
20771                    <div role="alert">
20772                      <span class="error" ng-show="myForm.input.$error.required">
20773                        Required!</span>
20774                      <span class="error" ng-show="myForm.input.$error.pattern">
20775                        Single word only!</span>
20776                    </div>
20777                    <tt>text = {{example.text}}</tt><br/>
20778                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20779                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20780                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20781                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20782                   </form>
20783                 </file>
20784                 <file name="protractor.js" type="protractor">
20785                   var text = element(by.binding('example.text'));
20786                   var valid = element(by.binding('myForm.input.$valid'));
20787                   var input = element(by.model('example.text'));
20788
20789                   it('should initialize to model', function() {
20790                     expect(text.getText()).toContain('guest');
20791                     expect(valid.getText()).toContain('true');
20792                   });
20793
20794                   it('should be invalid if empty', function() {
20795                     input.clear();
20796                     input.sendKeys('');
20797
20798                     expect(text.getText()).toEqual('text =');
20799                     expect(valid.getText()).toContain('false');
20800                   });
20801
20802                   it('should be invalid if multi word', function() {
20803                     input.clear();
20804                     input.sendKeys('hello world');
20805
20806                     expect(valid.getText()).toContain('false');
20807                   });
20808                 </file>
20809               </example>
20810            */
20811           'text': textInputType,
20812
20813             /**
20814              * @ngdoc input
20815              * @name input[date]
20816              *
20817              * @description
20818              * Input with date validation and transformation. In browsers that do not yet support
20819              * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
20820              * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
20821              * modern browsers do not yet support this input type, it is important to provide cues to users on the
20822              * expected input format via a placeholder or label.
20823              *
20824              * The model must always be a Date object, otherwise Angular will throw an error.
20825              * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20826              *
20827              * The timezone to be used to read/write the `Date` instance in the model can be defined using
20828              * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20829              *
20830              * @param {string} ngModel Assignable angular expression to data-bind to.
20831              * @param {string=} name Property name of the form under which the control is published.
20832              * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
20833              *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
20834              *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
20835              *   constraint validation.
20836              * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
20837              *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
20838              *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
20839              *   constraint validation.
20840              * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
20841              *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20842              * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
20843              *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20844              * @param {string=} required Sets `required` validation error key if the value is not entered.
20845              * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20846              *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20847              *    `required` when you want to data-bind to the `required` attribute.
20848              * @param {string=} ngChange Angular expression to be executed when input changes due to user
20849              *    interaction with the input element.
20850              *
20851              * @example
20852              <example name="date-input-directive" module="dateInputExample">
20853              <file name="index.html">
20854                <script>
20855                   angular.module('dateInputExample', [])
20856                     .controller('DateController', ['$scope', function($scope) {
20857                       $scope.example = {
20858                         value: new Date(2013, 9, 22)
20859                       };
20860                     }]);
20861                </script>
20862                <form name="myForm" ng-controller="DateController as dateCtrl">
20863                   <label for="exampleInput">Pick a date in 2013:</label>
20864                   <input type="date" id="exampleInput" name="input" ng-model="example.value"
20865                       placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
20866                   <div role="alert">
20867                     <span class="error" ng-show="myForm.input.$error.required">
20868                         Required!</span>
20869                     <span class="error" ng-show="myForm.input.$error.date">
20870                         Not a valid date!</span>
20871                    </div>
20872                    <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
20873                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20874                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20875                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20876                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20877                </form>
20878              </file>
20879              <file name="protractor.js" type="protractor">
20880                 var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
20881                 var valid = element(by.binding('myForm.input.$valid'));
20882                 var input = element(by.model('example.value'));
20883
20884                 // currently protractor/webdriver does not support
20885                 // sending keys to all known HTML5 input controls
20886                 // for various browsers (see https://github.com/angular/protractor/issues/562).
20887                 function setInput(val) {
20888                   // set the value of the element and force validation.
20889                   var scr = "var ipt = document.getElementById('exampleInput'); " +
20890                   "ipt.value = '" + val + "';" +
20891                   "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20892                   browser.executeScript(scr);
20893                 }
20894
20895                 it('should initialize to model', function() {
20896                   expect(value.getText()).toContain('2013-10-22');
20897                   expect(valid.getText()).toContain('myForm.input.$valid = true');
20898                 });
20899
20900                 it('should be invalid if empty', function() {
20901                   setInput('');
20902                   expect(value.getText()).toEqual('value =');
20903                   expect(valid.getText()).toContain('myForm.input.$valid = false');
20904                 });
20905
20906                 it('should be invalid if over max', function() {
20907                   setInput('2015-01-01');
20908                   expect(value.getText()).toContain('');
20909                   expect(valid.getText()).toContain('myForm.input.$valid = false');
20910                 });
20911              </file>
20912              </example>
20913              */
20914           'date': createDateInputType('date', DATE_REGEXP,
20915                  createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
20916                  'yyyy-MM-dd'),
20917
20918            /**
20919             * @ngdoc input
20920             * @name input[datetime-local]
20921             *
20922             * @description
20923             * Input with datetime validation and transformation. In browsers that do not yet support
20924             * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20925             * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
20926             *
20927             * The model must always be a Date object, otherwise Angular will throw an error.
20928             * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20929             *
20930             * The timezone to be used to read/write the `Date` instance in the model can be defined using
20931             * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20932             *
20933             * @param {string} ngModel Assignable angular expression to data-bind to.
20934             * @param {string=} name Property name of the form under which the control is published.
20935             * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
20936             *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
20937             *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
20938             *   Note that `min` will also add native HTML5 constraint validation.
20939             * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
20940             *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
20941             *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
20942             *   Note that `max` will also add native HTML5 constraint validation.
20943             * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
20944             *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20945             * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
20946             *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20947             * @param {string=} required Sets `required` validation error key if the value is not entered.
20948             * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20949             *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20950             *    `required` when you want to data-bind to the `required` attribute.
20951             * @param {string=} ngChange Angular expression to be executed when input changes due to user
20952             *    interaction with the input element.
20953             *
20954             * @example
20955             <example name="datetimelocal-input-directive" module="dateExample">
20956             <file name="index.html">
20957               <script>
20958                 angular.module('dateExample', [])
20959                   .controller('DateController', ['$scope', function($scope) {
20960                     $scope.example = {
20961                       value: new Date(2010, 11, 28, 14, 57)
20962                     };
20963                   }]);
20964               </script>
20965               <form name="myForm" ng-controller="DateController as dateCtrl">
20966                 <label for="exampleInput">Pick a date between in 2013:</label>
20967                 <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
20968                     placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
20969                 <div role="alert">
20970                   <span class="error" ng-show="myForm.input.$error.required">
20971                       Required!</span>
20972                   <span class="error" ng-show="myForm.input.$error.datetimelocal">
20973                       Not a valid date!</span>
20974                 </div>
20975                 <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
20976                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20977                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20978                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20979                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20980               </form>
20981             </file>
20982             <file name="protractor.js" type="protractor">
20983               var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
20984               var valid = element(by.binding('myForm.input.$valid'));
20985               var input = element(by.model('example.value'));
20986
20987               // currently protractor/webdriver does not support
20988               // sending keys to all known HTML5 input controls
20989               // for various browsers (https://github.com/angular/protractor/issues/562).
20990               function setInput(val) {
20991                 // set the value of the element and force validation.
20992                 var scr = "var ipt = document.getElementById('exampleInput'); " +
20993                 "ipt.value = '" + val + "';" +
20994                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20995                 browser.executeScript(scr);
20996               }
20997
20998               it('should initialize to model', function() {
20999                 expect(value.getText()).toContain('2010-12-28T14:57:00');
21000                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21001               });
21002
21003               it('should be invalid if empty', function() {
21004                 setInput('');
21005                 expect(value.getText()).toEqual('value =');
21006                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21007               });
21008
21009               it('should be invalid if over max', function() {
21010                 setInput('2015-01-01T23:59:00');
21011                 expect(value.getText()).toContain('');
21012                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21013               });
21014             </file>
21015             </example>
21016             */
21017           'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
21018               createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
21019               'yyyy-MM-ddTHH:mm:ss.sss'),
21020
21021           /**
21022            * @ngdoc input
21023            * @name input[time]
21024            *
21025            * @description
21026            * Input with time validation and transformation. In browsers that do not yet support
21027            * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21028            * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
21029            * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
21030            *
21031            * The model must always be a Date object, otherwise Angular will throw an error.
21032            * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21033            *
21034            * The timezone to be used to read/write the `Date` instance in the model can be defined using
21035            * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21036            *
21037            * @param {string} ngModel Assignable angular expression to data-bind to.
21038            * @param {string=} name Property name of the form under which the control is published.
21039            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21040            *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
21041            *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
21042            *   native HTML5 constraint validation.
21043            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21044            *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
21045            *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
21046            *   native HTML5 constraint validation.
21047            * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
21048            *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21049            * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
21050            *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21051            * @param {string=} required Sets `required` validation error key if the value is not entered.
21052            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21053            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21054            *    `required` when you want to data-bind to the `required` attribute.
21055            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21056            *    interaction with the input element.
21057            *
21058            * @example
21059            <example name="time-input-directive" module="timeExample">
21060            <file name="index.html">
21061              <script>
21062               angular.module('timeExample', [])
21063                 .controller('DateController', ['$scope', function($scope) {
21064                   $scope.example = {
21065                     value: new Date(1970, 0, 1, 14, 57, 0)
21066                   };
21067                 }]);
21068              </script>
21069              <form name="myForm" ng-controller="DateController as dateCtrl">
21070                 <label for="exampleInput">Pick a between 8am and 5pm:</label>
21071                 <input type="time" id="exampleInput" name="input" ng-model="example.value"
21072                     placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
21073                 <div role="alert">
21074                   <span class="error" ng-show="myForm.input.$error.required">
21075                       Required!</span>
21076                   <span class="error" ng-show="myForm.input.$error.time">
21077                       Not a valid date!</span>
21078                 </div>
21079                 <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
21080                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21081                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21082                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21083                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21084              </form>
21085            </file>
21086            <file name="protractor.js" type="protractor">
21087               var value = element(by.binding('example.value | date: "HH:mm:ss"'));
21088               var valid = element(by.binding('myForm.input.$valid'));
21089               var input = element(by.model('example.value'));
21090
21091               // currently protractor/webdriver does not support
21092               // sending keys to all known HTML5 input controls
21093               // for various browsers (https://github.com/angular/protractor/issues/562).
21094               function setInput(val) {
21095                 // set the value of the element and force validation.
21096                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21097                 "ipt.value = '" + val + "';" +
21098                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21099                 browser.executeScript(scr);
21100               }
21101
21102               it('should initialize to model', function() {
21103                 expect(value.getText()).toContain('14:57:00');
21104                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21105               });
21106
21107               it('should be invalid if empty', function() {
21108                 setInput('');
21109                 expect(value.getText()).toEqual('value =');
21110                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21111               });
21112
21113               it('should be invalid if over max', function() {
21114                 setInput('23:59:00');
21115                 expect(value.getText()).toContain('');
21116                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21117               });
21118            </file>
21119            </example>
21120            */
21121           'time': createDateInputType('time', TIME_REGEXP,
21122               createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
21123              'HH:mm:ss.sss'),
21124
21125            /**
21126             * @ngdoc input
21127             * @name input[week]
21128             *
21129             * @description
21130             * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
21131             * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21132             * week format (yyyy-W##), for example: `2013-W02`.
21133             *
21134             * The model must always be a Date object, otherwise Angular will throw an error.
21135             * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21136             *
21137             * The timezone to be used to read/write the `Date` instance in the model can be defined using
21138             * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21139             *
21140             * @param {string} ngModel Assignable angular expression to data-bind to.
21141             * @param {string=} name Property name of the form under which the control is published.
21142             * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21143             *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
21144             *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
21145             *   native HTML5 constraint validation.
21146             * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21147             *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
21148             *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
21149             *   native HTML5 constraint validation.
21150             * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
21151             *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21152             * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
21153             *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21154             * @param {string=} required Sets `required` validation error key if the value is not entered.
21155             * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21156             *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21157             *    `required` when you want to data-bind to the `required` attribute.
21158             * @param {string=} ngChange Angular expression to be executed when input changes due to user
21159             *    interaction with the input element.
21160             *
21161             * @example
21162             <example name="week-input-directive" module="weekExample">
21163             <file name="index.html">
21164               <script>
21165               angular.module('weekExample', [])
21166                 .controller('DateController', ['$scope', function($scope) {
21167                   $scope.example = {
21168                     value: new Date(2013, 0, 3)
21169                   };
21170                 }]);
21171               </script>
21172               <form name="myForm" ng-controller="DateController as dateCtrl">
21173                 <label>Pick a date between in 2013:
21174                   <input id="exampleInput" type="week" name="input" ng-model="example.value"
21175                          placeholder="YYYY-W##" min="2012-W32"
21176                          max="2013-W52" required />
21177                 </label>
21178                 <div role="alert">
21179                   <span class="error" ng-show="myForm.input.$error.required">
21180                       Required!</span>
21181                   <span class="error" ng-show="myForm.input.$error.week">
21182                       Not a valid date!</span>
21183                 </div>
21184                 <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
21185                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21186                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21187                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21188                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21189               </form>
21190             </file>
21191             <file name="protractor.js" type="protractor">
21192               var value = element(by.binding('example.value | date: "yyyy-Www"'));
21193               var valid = element(by.binding('myForm.input.$valid'));
21194               var input = element(by.model('example.value'));
21195
21196               // currently protractor/webdriver does not support
21197               // sending keys to all known HTML5 input controls
21198               // for various browsers (https://github.com/angular/protractor/issues/562).
21199               function setInput(val) {
21200                 // set the value of the element and force validation.
21201                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21202                 "ipt.value = '" + val + "';" +
21203                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21204                 browser.executeScript(scr);
21205               }
21206
21207               it('should initialize to model', function() {
21208                 expect(value.getText()).toContain('2013-W01');
21209                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21210               });
21211
21212               it('should be invalid if empty', function() {
21213                 setInput('');
21214                 expect(value.getText()).toEqual('value =');
21215                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21216               });
21217
21218               it('should be invalid if over max', function() {
21219                 setInput('2015-W01');
21220                 expect(value.getText()).toContain('');
21221                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21222               });
21223             </file>
21224             </example>
21225             */
21226           'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
21227
21228           /**
21229            * @ngdoc input
21230            * @name input[month]
21231            *
21232            * @description
21233            * Input with month validation and transformation. In browsers that do not yet support
21234            * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21235            * month format (yyyy-MM), for example: `2009-01`.
21236            *
21237            * The model must always be a Date object, otherwise Angular will throw an error.
21238            * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21239            * If the model is not set to the first of the month, the next view to model update will set it
21240            * to the first of the month.
21241            *
21242            * The timezone to be used to read/write the `Date` instance in the model can be defined using
21243            * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21244            *
21245            * @param {string} ngModel Assignable angular expression to data-bind to.
21246            * @param {string=} name Property name of the form under which the control is published.
21247            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21248            *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
21249            *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
21250            *   native HTML5 constraint validation.
21251            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21252            *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
21253            *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
21254            *   native HTML5 constraint validation.
21255            * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
21256            *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21257            * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
21258            *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21259
21260            * @param {string=} required Sets `required` validation error key if the value is not entered.
21261            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21262            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21263            *    `required` when you want to data-bind to the `required` attribute.
21264            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21265            *    interaction with the input element.
21266            *
21267            * @example
21268            <example name="month-input-directive" module="monthExample">
21269            <file name="index.html">
21270              <script>
21271               angular.module('monthExample', [])
21272                 .controller('DateController', ['$scope', function($scope) {
21273                   $scope.example = {
21274                     value: new Date(2013, 9, 1)
21275                   };
21276                 }]);
21277              </script>
21278              <form name="myForm" ng-controller="DateController as dateCtrl">
21279                <label for="exampleInput">Pick a month in 2013:</label>
21280                <input id="exampleInput" type="month" name="input" ng-model="example.value"
21281                   placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
21282                <div role="alert">
21283                  <span class="error" ng-show="myForm.input.$error.required">
21284                     Required!</span>
21285                  <span class="error" ng-show="myForm.input.$error.month">
21286                     Not a valid month!</span>
21287                </div>
21288                <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
21289                <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21290                <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21291                <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21292                <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21293              </form>
21294            </file>
21295            <file name="protractor.js" type="protractor">
21296               var value = element(by.binding('example.value | date: "yyyy-MM"'));
21297               var valid = element(by.binding('myForm.input.$valid'));
21298               var input = element(by.model('example.value'));
21299
21300               // currently protractor/webdriver does not support
21301               // sending keys to all known HTML5 input controls
21302               // for various browsers (https://github.com/angular/protractor/issues/562).
21303               function setInput(val) {
21304                 // set the value of the element and force validation.
21305                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21306                 "ipt.value = '" + val + "';" +
21307                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21308                 browser.executeScript(scr);
21309               }
21310
21311               it('should initialize to model', function() {
21312                 expect(value.getText()).toContain('2013-10');
21313                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21314               });
21315
21316               it('should be invalid if empty', function() {
21317                 setInput('');
21318                 expect(value.getText()).toEqual('value =');
21319                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21320               });
21321
21322               it('should be invalid if over max', function() {
21323                 setInput('2015-01');
21324                 expect(value.getText()).toContain('');
21325                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21326               });
21327            </file>
21328            </example>
21329            */
21330           'month': createDateInputType('month', MONTH_REGEXP,
21331              createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
21332              'yyyy-MM'),
21333
21334           /**
21335            * @ngdoc input
21336            * @name input[number]
21337            *
21338            * @description
21339            * Text input with number validation and transformation. Sets the `number` validation
21340            * error if not a valid number.
21341            *
21342            * <div class="alert alert-warning">
21343            * The model must always be of type `number` otherwise Angular will throw an error.
21344            * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
21345            * error docs for more information and an example of how to convert your model if necessary.
21346            * </div>
21347            *
21348            * ## Issues with HTML5 constraint validation
21349            *
21350            * In browsers that follow the
21351            * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
21352            * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
21353            * If a non-number is entered in the input, the browser will report the value as an empty string,
21354            * which means the view / model values in `ngModel` and subsequently the scope value
21355            * will also be an empty string.
21356            *
21357            *
21358            * @param {string} ngModel Assignable angular expression to data-bind to.
21359            * @param {string=} name Property name of the form under which the control is published.
21360            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21361            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21362            * @param {string=} required Sets `required` validation error key if the value is not entered.
21363            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21364            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21365            *    `required` when you want to data-bind to the `required` attribute.
21366            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21367            *    minlength.
21368            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21369            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21370            *    any length.
21371            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21372            *    that contains the regular expression body that will be converted to a regular expression
21373            *    as in the ngPattern directive.
21374            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21375            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21376            *    If the expression evaluates to a RegExp object, then this is used directly.
21377            *    If the expression evaluates to a string, then it will be converted to a RegExp
21378            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21379            *    `new RegExp('^abc$')`.<br />
21380            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21381            *    start at the index of the last search's match, thus not taking the whole input value into
21382            *    account.
21383            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21384            *    interaction with the input element.
21385            *
21386            * @example
21387               <example name="number-input-directive" module="numberExample">
21388                 <file name="index.html">
21389                  <script>
21390                    angular.module('numberExample', [])
21391                      .controller('ExampleController', ['$scope', function($scope) {
21392                        $scope.example = {
21393                          value: 12
21394                        };
21395                      }]);
21396                  </script>
21397                  <form name="myForm" ng-controller="ExampleController">
21398                    <label>Number:
21399                      <input type="number" name="input" ng-model="example.value"
21400                             min="0" max="99" required>
21401                   </label>
21402                    <div role="alert">
21403                      <span class="error" ng-show="myForm.input.$error.required">
21404                        Required!</span>
21405                      <span class="error" ng-show="myForm.input.$error.number">
21406                        Not valid number!</span>
21407                    </div>
21408                    <tt>value = {{example.value}}</tt><br/>
21409                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21410                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21411                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21412                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21413                   </form>
21414                 </file>
21415                 <file name="protractor.js" type="protractor">
21416                   var value = element(by.binding('example.value'));
21417                   var valid = element(by.binding('myForm.input.$valid'));
21418                   var input = element(by.model('example.value'));
21419
21420                   it('should initialize to model', function() {
21421                     expect(value.getText()).toContain('12');
21422                     expect(valid.getText()).toContain('true');
21423                   });
21424
21425                   it('should be invalid if empty', function() {
21426                     input.clear();
21427                     input.sendKeys('');
21428                     expect(value.getText()).toEqual('value =');
21429                     expect(valid.getText()).toContain('false');
21430                   });
21431
21432                   it('should be invalid if over max', function() {
21433                     input.clear();
21434                     input.sendKeys('123');
21435                     expect(value.getText()).toEqual('value =');
21436                     expect(valid.getText()).toContain('false');
21437                   });
21438                 </file>
21439               </example>
21440            */
21441           'number': numberInputType,
21442
21443
21444           /**
21445            * @ngdoc input
21446            * @name input[url]
21447            *
21448            * @description
21449            * Text input with URL validation. Sets the `url` validation error key if the content is not a
21450            * valid URL.
21451            *
21452            * <div class="alert alert-warning">
21453            * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
21454            * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
21455            * the built-in validators (see the {@link guide/forms Forms guide})
21456            * </div>
21457            *
21458            * @param {string} ngModel Assignable angular expression to data-bind to.
21459            * @param {string=} name Property name of the form under which the control is published.
21460            * @param {string=} required Sets `required` validation error key if the value is not entered.
21461            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21462            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21463            *    `required` when you want to data-bind to the `required` attribute.
21464            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21465            *    minlength.
21466            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21467            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21468            *    any length.
21469            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21470            *    that contains the regular expression body that will be converted to a regular expression
21471            *    as in the ngPattern directive.
21472            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21473            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21474            *    If the expression evaluates to a RegExp object, then this is used directly.
21475            *    If the expression evaluates to a string, then it will be converted to a RegExp
21476            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21477            *    `new RegExp('^abc$')`.<br />
21478            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21479            *    start at the index of the last search's match, thus not taking the whole input value into
21480            *    account.
21481            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21482            *    interaction with the input element.
21483            *
21484            * @example
21485               <example name="url-input-directive" module="urlExample">
21486                 <file name="index.html">
21487                  <script>
21488                    angular.module('urlExample', [])
21489                      .controller('ExampleController', ['$scope', function($scope) {
21490                        $scope.url = {
21491                          text: 'http://google.com'
21492                        };
21493                      }]);
21494                  </script>
21495                  <form name="myForm" ng-controller="ExampleController">
21496                    <label>URL:
21497                      <input type="url" name="input" ng-model="url.text" required>
21498                    <label>
21499                    <div role="alert">
21500                      <span class="error" ng-show="myForm.input.$error.required">
21501                        Required!</span>
21502                      <span class="error" ng-show="myForm.input.$error.url">
21503                        Not valid url!</span>
21504                    </div>
21505                    <tt>text = {{url.text}}</tt><br/>
21506                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21507                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21508                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21509                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21510                    <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
21511                   </form>
21512                 </file>
21513                 <file name="protractor.js" type="protractor">
21514                   var text = element(by.binding('url.text'));
21515                   var valid = element(by.binding('myForm.input.$valid'));
21516                   var input = element(by.model('url.text'));
21517
21518                   it('should initialize to model', function() {
21519                     expect(text.getText()).toContain('http://google.com');
21520                     expect(valid.getText()).toContain('true');
21521                   });
21522
21523                   it('should be invalid if empty', function() {
21524                     input.clear();
21525                     input.sendKeys('');
21526
21527                     expect(text.getText()).toEqual('text =');
21528                     expect(valid.getText()).toContain('false');
21529                   });
21530
21531                   it('should be invalid if not url', function() {
21532                     input.clear();
21533                     input.sendKeys('box');
21534
21535                     expect(valid.getText()).toContain('false');
21536                   });
21537                 </file>
21538               </example>
21539            */
21540           'url': urlInputType,
21541
21542
21543           /**
21544            * @ngdoc input
21545            * @name input[email]
21546            *
21547            * @description
21548            * Text input with email validation. Sets the `email` validation error key if not a valid email
21549            * address.
21550            *
21551            * <div class="alert alert-warning">
21552            * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
21553            * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
21554            * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
21555            * </div>
21556            *
21557            * @param {string} ngModel Assignable angular expression to data-bind to.
21558            * @param {string=} name Property name of the form under which the control is published.
21559            * @param {string=} required Sets `required` validation error key if the value is not entered.
21560            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21561            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21562            *    `required` when you want to data-bind to the `required` attribute.
21563            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21564            *    minlength.
21565            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21566            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21567            *    any length.
21568            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21569            *    that contains the regular expression body that will be converted to a regular expression
21570            *    as in the ngPattern directive.
21571            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21572            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21573            *    If the expression evaluates to a RegExp object, then this is used directly.
21574            *    If the expression evaluates to a string, then it will be converted to a RegExp
21575            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21576            *    `new RegExp('^abc$')`.<br />
21577            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21578            *    start at the index of the last search's match, thus not taking the whole input value into
21579            *    account.
21580            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21581            *    interaction with the input element.
21582            *
21583            * @example
21584               <example name="email-input-directive" module="emailExample">
21585                 <file name="index.html">
21586                  <script>
21587                    angular.module('emailExample', [])
21588                      .controller('ExampleController', ['$scope', function($scope) {
21589                        $scope.email = {
21590                          text: 'me@example.com'
21591                        };
21592                      }]);
21593                  </script>
21594                    <form name="myForm" ng-controller="ExampleController">
21595                      <label>Email:
21596                        <input type="email" name="input" ng-model="email.text" required>
21597                      </label>
21598                      <div role="alert">
21599                        <span class="error" ng-show="myForm.input.$error.required">
21600                          Required!</span>
21601                        <span class="error" ng-show="myForm.input.$error.email">
21602                          Not valid email!</span>
21603                      </div>
21604                      <tt>text = {{email.text}}</tt><br/>
21605                      <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21606                      <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21607                      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21608                      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21609                      <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
21610                    </form>
21611                  </file>
21612                 <file name="protractor.js" type="protractor">
21613                   var text = element(by.binding('email.text'));
21614                   var valid = element(by.binding('myForm.input.$valid'));
21615                   var input = element(by.model('email.text'));
21616
21617                   it('should initialize to model', function() {
21618                     expect(text.getText()).toContain('me@example.com');
21619                     expect(valid.getText()).toContain('true');
21620                   });
21621
21622                   it('should be invalid if empty', function() {
21623                     input.clear();
21624                     input.sendKeys('');
21625                     expect(text.getText()).toEqual('text =');
21626                     expect(valid.getText()).toContain('false');
21627                   });
21628
21629                   it('should be invalid if not email', function() {
21630                     input.clear();
21631                     input.sendKeys('xxx');
21632
21633                     expect(valid.getText()).toContain('false');
21634                   });
21635                 </file>
21636               </example>
21637            */
21638           'email': emailInputType,
21639
21640
21641           /**
21642            * @ngdoc input
21643            * @name input[radio]
21644            *
21645            * @description
21646            * HTML radio button.
21647            *
21648            * @param {string} ngModel Assignable angular expression to data-bind to.
21649            * @param {string} value The value to which the `ngModel` expression should be set when selected.
21650            *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
21651            *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
21652            * @param {string=} name Property name of the form under which the control is published.
21653            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21654            *    interaction with the input element.
21655            * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
21656            *    is selected. Should be used instead of the `value` attribute if you need
21657            *    a non-string `ngModel` (`boolean`, `array`, ...).
21658            *
21659            * @example
21660               <example name="radio-input-directive" module="radioExample">
21661                 <file name="index.html">
21662                  <script>
21663                    angular.module('radioExample', [])
21664                      .controller('ExampleController', ['$scope', function($scope) {
21665                        $scope.color = {
21666                          name: 'blue'
21667                        };
21668                        $scope.specialValue = {
21669                          "id": "12345",
21670                          "value": "green"
21671                        };
21672                      }]);
21673                  </script>
21674                  <form name="myForm" ng-controller="ExampleController">
21675                    <label>
21676                      <input type="radio" ng-model="color.name" value="red">
21677                      Red
21678                    </label><br/>
21679                    <label>
21680                      <input type="radio" ng-model="color.name" ng-value="specialValue">
21681                      Green
21682                    </label><br/>
21683                    <label>
21684                      <input type="radio" ng-model="color.name" value="blue">
21685                      Blue
21686                    </label><br/>
21687                    <tt>color = {{color.name | json}}</tt><br/>
21688                   </form>
21689                   Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
21690                 </file>
21691                 <file name="protractor.js" type="protractor">
21692                   it('should change state', function() {
21693                     var color = element(by.binding('color.name'));
21694
21695                     expect(color.getText()).toContain('blue');
21696
21697                     element.all(by.model('color.name')).get(0).click();
21698
21699                     expect(color.getText()).toContain('red');
21700                   });
21701                 </file>
21702               </example>
21703            */
21704           'radio': radioInputType,
21705
21706
21707           /**
21708            * @ngdoc input
21709            * @name input[checkbox]
21710            *
21711            * @description
21712            * HTML checkbox.
21713            *
21714            * @param {string} ngModel Assignable angular expression to data-bind to.
21715            * @param {string=} name Property name of the form under which the control is published.
21716            * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
21717            * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
21718            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21719            *    interaction with the input element.
21720            *
21721            * @example
21722               <example name="checkbox-input-directive" module="checkboxExample">
21723                 <file name="index.html">
21724                  <script>
21725                    angular.module('checkboxExample', [])
21726                      .controller('ExampleController', ['$scope', function($scope) {
21727                        $scope.checkboxModel = {
21728                         value1 : true,
21729                         value2 : 'YES'
21730                       };
21731                      }]);
21732                  </script>
21733                  <form name="myForm" ng-controller="ExampleController">
21734                    <label>Value1:
21735                      <input type="checkbox" ng-model="checkboxModel.value1">
21736                    </label><br/>
21737                    <label>Value2:
21738                      <input type="checkbox" ng-model="checkboxModel.value2"
21739                             ng-true-value="'YES'" ng-false-value="'NO'">
21740                     </label><br/>
21741                    <tt>value1 = {{checkboxModel.value1}}</tt><br/>
21742                    <tt>value2 = {{checkboxModel.value2}}</tt><br/>
21743                   </form>
21744                 </file>
21745                 <file name="protractor.js" type="protractor">
21746                   it('should change state', function() {
21747                     var value1 = element(by.binding('checkboxModel.value1'));
21748                     var value2 = element(by.binding('checkboxModel.value2'));
21749
21750                     expect(value1.getText()).toContain('true');
21751                     expect(value2.getText()).toContain('YES');
21752
21753                     element(by.model('checkboxModel.value1')).click();
21754                     element(by.model('checkboxModel.value2')).click();
21755
21756                     expect(value1.getText()).toContain('false');
21757                     expect(value2.getText()).toContain('NO');
21758                   });
21759                 </file>
21760               </example>
21761            */
21762           'checkbox': checkboxInputType,
21763
21764           'hidden': noop,
21765           'button': noop,
21766           'submit': noop,
21767           'reset': noop,
21768           'file': noop
21769         };
21770
21771         function stringBasedInputType(ctrl) {
21772           ctrl.$formatters.push(function(value) {
21773             return ctrl.$isEmpty(value) ? value : value.toString();
21774           });
21775         }
21776
21777         function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21778           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21779           stringBasedInputType(ctrl);
21780         }
21781
21782         function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21783           var type = lowercase(element[0].type);
21784
21785           // In composition mode, users are still inputing intermediate text buffer,
21786           // hold the listener until composition is done.
21787           // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
21788           if (!$sniffer.android) {
21789             var composing = false;
21790
21791             element.on('compositionstart', function(data) {
21792               composing = true;
21793             });
21794
21795             element.on('compositionend', function() {
21796               composing = false;
21797               listener();
21798             });
21799           }
21800
21801           var listener = function(ev) {
21802             if (timeout) {
21803               $browser.defer.cancel(timeout);
21804               timeout = null;
21805             }
21806             if (composing) return;
21807             var value = element.val(),
21808                 event = ev && ev.type;
21809
21810             // By default we will trim the value
21811             // If the attribute ng-trim exists we will avoid trimming
21812             // If input type is 'password', the value is never trimmed
21813             if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
21814               value = trim(value);
21815             }
21816
21817             // If a control is suffering from bad input (due to native validators), browsers discard its
21818             // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
21819             // control's value is the same empty value twice in a row.
21820             if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
21821               ctrl.$setViewValue(value, event);
21822             }
21823           };
21824
21825           // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
21826           // input event on backspace, delete or cut
21827           if ($sniffer.hasEvent('input')) {
21828             element.on('input', listener);
21829           } else {
21830             var timeout;
21831
21832             var deferListener = function(ev, input, origValue) {
21833               if (!timeout) {
21834                 timeout = $browser.defer(function() {
21835                   timeout = null;
21836                   if (!input || input.value !== origValue) {
21837                     listener(ev);
21838                   }
21839                 });
21840               }
21841             };
21842
21843             element.on('keydown', function(event) {
21844               var key = event.keyCode;
21845
21846               // ignore
21847               //    command            modifiers                   arrows
21848               if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
21849
21850               deferListener(event, this, this.value);
21851             });
21852
21853             // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
21854             if ($sniffer.hasEvent('paste')) {
21855               element.on('paste cut', deferListener);
21856             }
21857           }
21858
21859           // if user paste into input using mouse on older browser
21860           // or form autocomplete on newer browser, we need "change" event to catch it
21861           element.on('change', listener);
21862
21863           ctrl.$render = function() {
21864             // Workaround for Firefox validation #12102.
21865             var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
21866             if (element.val() !== value) {
21867               element.val(value);
21868             }
21869           };
21870         }
21871
21872         function weekParser(isoWeek, existingDate) {
21873           if (isDate(isoWeek)) {
21874             return isoWeek;
21875           }
21876
21877           if (isString(isoWeek)) {
21878             WEEK_REGEXP.lastIndex = 0;
21879             var parts = WEEK_REGEXP.exec(isoWeek);
21880             if (parts) {
21881               var year = +parts[1],
21882                   week = +parts[2],
21883                   hours = 0,
21884                   minutes = 0,
21885                   seconds = 0,
21886                   milliseconds = 0,
21887                   firstThurs = getFirstThursdayOfYear(year),
21888                   addDays = (week - 1) * 7;
21889
21890               if (existingDate) {
21891                 hours = existingDate.getHours();
21892                 minutes = existingDate.getMinutes();
21893                 seconds = existingDate.getSeconds();
21894                 milliseconds = existingDate.getMilliseconds();
21895               }
21896
21897               return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
21898             }
21899           }
21900
21901           return NaN;
21902         }
21903
21904         function createDateParser(regexp, mapping) {
21905           return function(iso, date) {
21906             var parts, map;
21907
21908             if (isDate(iso)) {
21909               return iso;
21910             }
21911
21912             if (isString(iso)) {
21913               // When a date is JSON'ified to wraps itself inside of an extra
21914               // set of double quotes. This makes the date parsing code unable
21915               // to match the date string and parse it as a date.
21916               if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
21917                 iso = iso.substring(1, iso.length - 1);
21918               }
21919               if (ISO_DATE_REGEXP.test(iso)) {
21920                 return new Date(iso);
21921               }
21922               regexp.lastIndex = 0;
21923               parts = regexp.exec(iso);
21924
21925               if (parts) {
21926                 parts.shift();
21927                 if (date) {
21928                   map = {
21929                     yyyy: date.getFullYear(),
21930                     MM: date.getMonth() + 1,
21931                     dd: date.getDate(),
21932                     HH: date.getHours(),
21933                     mm: date.getMinutes(),
21934                     ss: date.getSeconds(),
21935                     sss: date.getMilliseconds() / 1000
21936                   };
21937                 } else {
21938                   map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
21939                 }
21940
21941                 forEach(parts, function(part, index) {
21942                   if (index < mapping.length) {
21943                     map[mapping[index]] = +part;
21944                   }
21945                 });
21946                 return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
21947               }
21948             }
21949
21950             return NaN;
21951           };
21952         }
21953
21954         function createDateInputType(type, regexp, parseDate, format) {
21955           return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
21956             badInputChecker(scope, element, attr, ctrl);
21957             baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21958             var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
21959             var previousDate;
21960
21961             ctrl.$$parserName = type;
21962             ctrl.$parsers.push(function(value) {
21963               if (ctrl.$isEmpty(value)) return null;
21964               if (regexp.test(value)) {
21965                 // Note: We cannot read ctrl.$modelValue, as there might be a different
21966                 // parser/formatter in the processing chain so that the model
21967                 // contains some different data format!
21968                 var parsedDate = parseDate(value, previousDate);
21969                 if (timezone) {
21970                   parsedDate = convertTimezoneToLocal(parsedDate, timezone);
21971                 }
21972                 return parsedDate;
21973               }
21974               return undefined;
21975             });
21976
21977             ctrl.$formatters.push(function(value) {
21978               if (value && !isDate(value)) {
21979                 throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
21980               }
21981               if (isValidDate(value)) {
21982                 previousDate = value;
21983                 if (previousDate && timezone) {
21984                   previousDate = convertTimezoneToLocal(previousDate, timezone, true);
21985                 }
21986                 return $filter('date')(value, format, timezone);
21987               } else {
21988                 previousDate = null;
21989                 return '';
21990               }
21991             });
21992
21993             if (isDefined(attr.min) || attr.ngMin) {
21994               var minVal;
21995               ctrl.$validators.min = function(value) {
21996                 return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
21997               };
21998               attr.$observe('min', function(val) {
21999                 minVal = parseObservedDateValue(val);
22000                 ctrl.$validate();
22001               });
22002             }
22003
22004             if (isDefined(attr.max) || attr.ngMax) {
22005               var maxVal;
22006               ctrl.$validators.max = function(value) {
22007                 return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
22008               };
22009               attr.$observe('max', function(val) {
22010                 maxVal = parseObservedDateValue(val);
22011                 ctrl.$validate();
22012               });
22013             }
22014
22015             function isValidDate(value) {
22016               // Invalid Date: getTime() returns NaN
22017               return value && !(value.getTime && value.getTime() !== value.getTime());
22018             }
22019
22020             function parseObservedDateValue(val) {
22021               return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
22022             }
22023           };
22024         }
22025
22026         function badInputChecker(scope, element, attr, ctrl) {
22027           var node = element[0];
22028           var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
22029           if (nativeValidation) {
22030             ctrl.$parsers.push(function(value) {
22031               var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
22032               // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
22033               // - also sets validity.badInput (should only be validity.typeMismatch).
22034               // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
22035               // - can ignore this case as we can still read out the erroneous email...
22036               return validity.badInput && !validity.typeMismatch ? undefined : value;
22037             });
22038           }
22039         }
22040
22041         function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22042           badInputChecker(scope, element, attr, ctrl);
22043           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22044
22045           ctrl.$$parserName = 'number';
22046           ctrl.$parsers.push(function(value) {
22047             if (ctrl.$isEmpty(value))      return null;
22048             if (NUMBER_REGEXP.test(value)) return parseFloat(value);
22049             return undefined;
22050           });
22051
22052           ctrl.$formatters.push(function(value) {
22053             if (!ctrl.$isEmpty(value)) {
22054               if (!isNumber(value)) {
22055                 throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
22056               }
22057               value = value.toString();
22058             }
22059             return value;
22060           });
22061
22062           if (isDefined(attr.min) || attr.ngMin) {
22063             var minVal;
22064             ctrl.$validators.min = function(value) {
22065               return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
22066             };
22067
22068             attr.$observe('min', function(val) {
22069               if (isDefined(val) && !isNumber(val)) {
22070                 val = parseFloat(val, 10);
22071               }
22072               minVal = isNumber(val) && !isNaN(val) ? val : undefined;
22073               // TODO(matsko): implement validateLater to reduce number of validations
22074               ctrl.$validate();
22075             });
22076           }
22077
22078           if (isDefined(attr.max) || attr.ngMax) {
22079             var maxVal;
22080             ctrl.$validators.max = function(value) {
22081               return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
22082             };
22083
22084             attr.$observe('max', function(val) {
22085               if (isDefined(val) && !isNumber(val)) {
22086                 val = parseFloat(val, 10);
22087               }
22088               maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
22089               // TODO(matsko): implement validateLater to reduce number of validations
22090               ctrl.$validate();
22091             });
22092           }
22093         }
22094
22095         function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22096           // Note: no badInputChecker here by purpose as `url` is only a validation
22097           // in browsers, i.e. we can always read out input.value even if it is not valid!
22098           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22099           stringBasedInputType(ctrl);
22100
22101           ctrl.$$parserName = 'url';
22102           ctrl.$validators.url = function(modelValue, viewValue) {
22103             var value = modelValue || viewValue;
22104             return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
22105           };
22106         }
22107
22108         function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22109           // Note: no badInputChecker here by purpose as `url` is only a validation
22110           // in browsers, i.e. we can always read out input.value even if it is not valid!
22111           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22112           stringBasedInputType(ctrl);
22113
22114           ctrl.$$parserName = 'email';
22115           ctrl.$validators.email = function(modelValue, viewValue) {
22116             var value = modelValue || viewValue;
22117             return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
22118           };
22119         }
22120
22121         function radioInputType(scope, element, attr, ctrl) {
22122           // make the name unique, if not defined
22123           if (isUndefined(attr.name)) {
22124             element.attr('name', nextUid());
22125           }
22126
22127           var listener = function(ev) {
22128             if (element[0].checked) {
22129               ctrl.$setViewValue(attr.value, ev && ev.type);
22130             }
22131           };
22132
22133           element.on('click', listener);
22134
22135           ctrl.$render = function() {
22136             var value = attr.value;
22137             element[0].checked = (value == ctrl.$viewValue);
22138           };
22139
22140           attr.$observe('value', ctrl.$render);
22141         }
22142
22143         function parseConstantExpr($parse, context, name, expression, fallback) {
22144           var parseFn;
22145           if (isDefined(expression)) {
22146             parseFn = $parse(expression);
22147             if (!parseFn.constant) {
22148               throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
22149                                            '`{1}`.', name, expression);
22150             }
22151             return parseFn(context);
22152           }
22153           return fallback;
22154         }
22155
22156         function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
22157           var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
22158           var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
22159
22160           var listener = function(ev) {
22161             ctrl.$setViewValue(element[0].checked, ev && ev.type);
22162           };
22163
22164           element.on('click', listener);
22165
22166           ctrl.$render = function() {
22167             element[0].checked = ctrl.$viewValue;
22168           };
22169
22170           // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
22171           // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
22172           // it to a boolean.
22173           ctrl.$isEmpty = function(value) {
22174             return value === false;
22175           };
22176
22177           ctrl.$formatters.push(function(value) {
22178             return equals(value, trueValue);
22179           });
22180
22181           ctrl.$parsers.push(function(value) {
22182             return value ? trueValue : falseValue;
22183           });
22184         }
22185
22186
22187         /**
22188          * @ngdoc directive
22189          * @name textarea
22190          * @restrict E
22191          *
22192          * @description
22193          * HTML textarea element control with angular data-binding. The data-binding and validation
22194          * properties of this element are exactly the same as those of the
22195          * {@link ng.directive:input input element}.
22196          *
22197          * @param {string} ngModel Assignable angular expression to data-bind to.
22198          * @param {string=} name Property name of the form under which the control is published.
22199          * @param {string=} required Sets `required` validation error key if the value is not entered.
22200          * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
22201          *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
22202          *    `required` when you want to data-bind to the `required` attribute.
22203          * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22204          *    minlength.
22205          * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22206          *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22207          *    length.
22208          * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22209          *    a RegExp found by evaluating the Angular expression given in the attribute value.
22210          *    If the expression evaluates to a RegExp object, then this is used directly.
22211          *    If the expression evaluates to a string, then it will be converted to a RegExp
22212          *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
22213          *    `new RegExp('^abc$')`.<br />
22214          *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
22215          *    start at the index of the last search's match, thus not taking the whole input value into
22216          *    account.
22217          * @param {string=} ngChange Angular expression to be executed when input changes due to user
22218          *    interaction with the input element.
22219          * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22220          */
22221
22222
22223         /**
22224          * @ngdoc directive
22225          * @name input
22226          * @restrict E
22227          *
22228          * @description
22229          * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
22230          * input state control, and validation.
22231          * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
22232          *
22233          * <div class="alert alert-warning">
22234          * **Note:** Not every feature offered is available for all input types.
22235          * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
22236          * </div>
22237          *
22238          * @param {string} ngModel Assignable angular expression to data-bind to.
22239          * @param {string=} name Property name of the form under which the control is published.
22240          * @param {string=} required Sets `required` validation error key if the value is not entered.
22241          * @param {boolean=} ngRequired Sets `required` attribute if set to true
22242          * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22243          *    minlength.
22244          * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22245          *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22246          *    length.
22247          * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22248          *    a RegExp found by evaluating the Angular expression given in the attribute value.
22249          *    If the expression evaluates to a RegExp object, then this is used directly.
22250          *    If the expression evaluates to a string, then it will be converted to a RegExp
22251          *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
22252          *    `new RegExp('^abc$')`.<br />
22253          *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
22254          *    start at the index of the last search's match, thus not taking the whole input value into
22255          *    account.
22256          * @param {string=} ngChange Angular expression to be executed when input changes due to user
22257          *    interaction with the input element.
22258          * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22259          *    This parameter is ignored for input[type=password] controls, which will never trim the
22260          *    input.
22261          *
22262          * @example
22263             <example name="input-directive" module="inputExample">
22264               <file name="index.html">
22265                <script>
22266                   angular.module('inputExample', [])
22267                     .controller('ExampleController', ['$scope', function($scope) {
22268                       $scope.user = {name: 'guest', last: 'visitor'};
22269                     }]);
22270                </script>
22271                <div ng-controller="ExampleController">
22272                  <form name="myForm">
22273                    <label>
22274                       User name:
22275                       <input type="text" name="userName" ng-model="user.name" required>
22276                    </label>
22277                    <div role="alert">
22278                      <span class="error" ng-show="myForm.userName.$error.required">
22279                       Required!</span>
22280                    </div>
22281                    <label>
22282                       Last name:
22283                       <input type="text" name="lastName" ng-model="user.last"
22284                       ng-minlength="3" ng-maxlength="10">
22285                    </label>
22286                    <div role="alert">
22287                      <span class="error" ng-show="myForm.lastName.$error.minlength">
22288                        Too short!</span>
22289                      <span class="error" ng-show="myForm.lastName.$error.maxlength">
22290                        Too long!</span>
22291                    </div>
22292                  </form>
22293                  <hr>
22294                  <tt>user = {{user}}</tt><br/>
22295                  <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
22296                  <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
22297                  <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
22298                  <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
22299                  <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
22300                  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
22301                  <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
22302                  <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
22303                </div>
22304               </file>
22305               <file name="protractor.js" type="protractor">
22306                 var user = element(by.exactBinding('user'));
22307                 var userNameValid = element(by.binding('myForm.userName.$valid'));
22308                 var lastNameValid = element(by.binding('myForm.lastName.$valid'));
22309                 var lastNameError = element(by.binding('myForm.lastName.$error'));
22310                 var formValid = element(by.binding('myForm.$valid'));
22311                 var userNameInput = element(by.model('user.name'));
22312                 var userLastInput = element(by.model('user.last'));
22313
22314                 it('should initialize to model', function() {
22315                   expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
22316                   expect(userNameValid.getText()).toContain('true');
22317                   expect(formValid.getText()).toContain('true');
22318                 });
22319
22320                 it('should be invalid if empty when required', function() {
22321                   userNameInput.clear();
22322                   userNameInput.sendKeys('');
22323
22324                   expect(user.getText()).toContain('{"last":"visitor"}');
22325                   expect(userNameValid.getText()).toContain('false');
22326                   expect(formValid.getText()).toContain('false');
22327                 });
22328
22329                 it('should be valid if empty when min length is set', function() {
22330                   userLastInput.clear();
22331                   userLastInput.sendKeys('');
22332
22333                   expect(user.getText()).toContain('{"name":"guest","last":""}');
22334                   expect(lastNameValid.getText()).toContain('true');
22335                   expect(formValid.getText()).toContain('true');
22336                 });
22337
22338                 it('should be invalid if less than required min length', function() {
22339                   userLastInput.clear();
22340                   userLastInput.sendKeys('xx');
22341
22342                   expect(user.getText()).toContain('{"name":"guest"}');
22343                   expect(lastNameValid.getText()).toContain('false');
22344                   expect(lastNameError.getText()).toContain('minlength');
22345                   expect(formValid.getText()).toContain('false');
22346                 });
22347
22348                 it('should be invalid if longer than max length', function() {
22349                   userLastInput.clear();
22350                   userLastInput.sendKeys('some ridiculously long name');
22351
22352                   expect(user.getText()).toContain('{"name":"guest"}');
22353                   expect(lastNameValid.getText()).toContain('false');
22354                   expect(lastNameError.getText()).toContain('maxlength');
22355                   expect(formValid.getText()).toContain('false');
22356                 });
22357               </file>
22358             </example>
22359          */
22360         var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
22361             function($browser, $sniffer, $filter, $parse) {
22362           return {
22363             restrict: 'E',
22364             require: ['?ngModel'],
22365             link: {
22366               pre: function(scope, element, attr, ctrls) {
22367                 if (ctrls[0]) {
22368                   (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
22369                                                                       $browser, $filter, $parse);
22370                 }
22371               }
22372             }
22373           };
22374         }];
22375
22376
22377
22378         var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
22379         /**
22380          * @ngdoc directive
22381          * @name ngValue
22382          *
22383          * @description
22384          * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
22385          * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
22386          * the bound value.
22387          *
22388          * `ngValue` is useful when dynamically generating lists of radio buttons using
22389          * {@link ngRepeat `ngRepeat`}, as shown below.
22390          *
22391          * Likewise, `ngValue` can be used to generate `<option>` elements for
22392          * the {@link select `select`} element. In that case however, only strings are supported
22393          * for the `value `attribute, so the resulting `ngModel` will always be a string.
22394          * Support for `select` models with non-string values is available via `ngOptions`.
22395          *
22396          * @element input
22397          * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
22398          *   of the `input` element
22399          *
22400          * @example
22401             <example name="ngValue-directive" module="valueExample">
22402               <file name="index.html">
22403                <script>
22404                   angular.module('valueExample', [])
22405                     .controller('ExampleController', ['$scope', function($scope) {
22406                       $scope.names = ['pizza', 'unicorns', 'robots'];
22407                       $scope.my = { favorite: 'unicorns' };
22408                     }]);
22409                </script>
22410                 <form ng-controller="ExampleController">
22411                   <h2>Which is your favorite?</h2>
22412                     <label ng-repeat="name in names" for="{{name}}">
22413                       {{name}}
22414                       <input type="radio"
22415                              ng-model="my.favorite"
22416                              ng-value="name"
22417                              id="{{name}}"
22418                              name="favorite">
22419                     </label>
22420                   <div>You chose {{my.favorite}}</div>
22421                 </form>
22422               </file>
22423               <file name="protractor.js" type="protractor">
22424                 var favorite = element(by.binding('my.favorite'));
22425
22426                 it('should initialize to model', function() {
22427                   expect(favorite.getText()).toContain('unicorns');
22428                 });
22429                 it('should bind the values to the inputs', function() {
22430                   element.all(by.model('my.favorite')).get(0).click();
22431                   expect(favorite.getText()).toContain('pizza');
22432                 });
22433               </file>
22434             </example>
22435          */
22436         var ngValueDirective = function() {
22437           return {
22438             restrict: 'A',
22439             priority: 100,
22440             compile: function(tpl, tplAttr) {
22441               if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
22442                 return function ngValueConstantLink(scope, elm, attr) {
22443                   attr.$set('value', scope.$eval(attr.ngValue));
22444                 };
22445               } else {
22446                 return function ngValueLink(scope, elm, attr) {
22447                   scope.$watch(attr.ngValue, function valueWatchAction(value) {
22448                     attr.$set('value', value);
22449                   });
22450                 };
22451               }
22452             }
22453           };
22454         };
22455
22456         /**
22457          * @ngdoc directive
22458          * @name ngBind
22459          * @restrict AC
22460          *
22461          * @description
22462          * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
22463          * with the value of a given expression, and to update the text content when the value of that
22464          * expression changes.
22465          *
22466          * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
22467          * `{{ expression }}` which is similar but less verbose.
22468          *
22469          * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
22470          * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
22471          * element attribute, it makes the bindings invisible to the user while the page is loading.
22472          *
22473          * An alternative solution to this problem would be using the
22474          * {@link ng.directive:ngCloak ngCloak} directive.
22475          *
22476          *
22477          * @element ANY
22478          * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
22479          *
22480          * @example
22481          * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
22482            <example module="bindExample">
22483              <file name="index.html">
22484                <script>
22485                  angular.module('bindExample', [])
22486                    .controller('ExampleController', ['$scope', function($scope) {
22487                      $scope.name = 'Whirled';
22488                    }]);
22489                </script>
22490                <div ng-controller="ExampleController">
22491                  <label>Enter name: <input type="text" ng-model="name"></label><br>
22492                  Hello <span ng-bind="name"></span>!
22493                </div>
22494              </file>
22495              <file name="protractor.js" type="protractor">
22496                it('should check ng-bind', function() {
22497                  var nameInput = element(by.model('name'));
22498
22499                  expect(element(by.binding('name')).getText()).toBe('Whirled');
22500                  nameInput.clear();
22501                  nameInput.sendKeys('world');
22502                  expect(element(by.binding('name')).getText()).toBe('world');
22503                });
22504              </file>
22505            </example>
22506          */
22507         var ngBindDirective = ['$compile', function($compile) {
22508           return {
22509             restrict: 'AC',
22510             compile: function ngBindCompile(templateElement) {
22511               $compile.$$addBindingClass(templateElement);
22512               return function ngBindLink(scope, element, attr) {
22513                 $compile.$$addBindingInfo(element, attr.ngBind);
22514                 element = element[0];
22515                 scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
22516                   element.textContent = isUndefined(value) ? '' : value;
22517                 });
22518               };
22519             }
22520           };
22521         }];
22522
22523
22524         /**
22525          * @ngdoc directive
22526          * @name ngBindTemplate
22527          *
22528          * @description
22529          * The `ngBindTemplate` directive specifies that the element
22530          * text content should be replaced with the interpolation of the template
22531          * in the `ngBindTemplate` attribute.
22532          * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
22533          * expressions. This directive is needed since some HTML elements
22534          * (such as TITLE and OPTION) cannot contain SPAN elements.
22535          *
22536          * @element ANY
22537          * @param {string} ngBindTemplate template of form
22538          *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
22539          *
22540          * @example
22541          * Try it here: enter text in text box and watch the greeting change.
22542            <example module="bindExample">
22543              <file name="index.html">
22544                <script>
22545                  angular.module('bindExample', [])
22546                    .controller('ExampleController', ['$scope', function($scope) {
22547                      $scope.salutation = 'Hello';
22548                      $scope.name = 'World';
22549                    }]);
22550                </script>
22551                <div ng-controller="ExampleController">
22552                 <label>Salutation: <input type="text" ng-model="salutation"></label><br>
22553                 <label>Name: <input type="text" ng-model="name"></label><br>
22554                 <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
22555                </div>
22556              </file>
22557              <file name="protractor.js" type="protractor">
22558                it('should check ng-bind', function() {
22559                  var salutationElem = element(by.binding('salutation'));
22560                  var salutationInput = element(by.model('salutation'));
22561                  var nameInput = element(by.model('name'));
22562
22563                  expect(salutationElem.getText()).toBe('Hello World!');
22564
22565                  salutationInput.clear();
22566                  salutationInput.sendKeys('Greetings');
22567                  nameInput.clear();
22568                  nameInput.sendKeys('user');
22569
22570                  expect(salutationElem.getText()).toBe('Greetings user!');
22571                });
22572              </file>
22573            </example>
22574          */
22575         var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
22576           return {
22577             compile: function ngBindTemplateCompile(templateElement) {
22578               $compile.$$addBindingClass(templateElement);
22579               return function ngBindTemplateLink(scope, element, attr) {
22580                 var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
22581                 $compile.$$addBindingInfo(element, interpolateFn.expressions);
22582                 element = element[0];
22583                 attr.$observe('ngBindTemplate', function(value) {
22584                   element.textContent = isUndefined(value) ? '' : value;
22585                 });
22586               };
22587             }
22588           };
22589         }];
22590
22591
22592         /**
22593          * @ngdoc directive
22594          * @name ngBindHtml
22595          *
22596          * @description
22597          * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
22598          * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
22599          * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
22600          * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
22601          * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
22602          *
22603          * You may also bypass sanitization for values you know are safe. To do so, bind to
22604          * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
22605          * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
22606          *
22607          * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
22608          * will have an exception (instead of an exploit.)
22609          *
22610          * @element ANY
22611          * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
22612          *
22613          * @example
22614
22615            <example module="bindHtmlExample" deps="angular-sanitize.js">
22616              <file name="index.html">
22617                <div ng-controller="ExampleController">
22618                 <p ng-bind-html="myHTML"></p>
22619                </div>
22620              </file>
22621
22622              <file name="script.js">
22623                angular.module('bindHtmlExample', ['ngSanitize'])
22624                  .controller('ExampleController', ['$scope', function($scope) {
22625                    $scope.myHTML =
22626                       'I am an <code>HTML</code>string with ' +
22627                       '<a href="#">links!</a> and other <em>stuff</em>';
22628                  }]);
22629              </file>
22630
22631              <file name="protractor.js" type="protractor">
22632                it('should check ng-bind-html', function() {
22633                  expect(element(by.binding('myHTML')).getText()).toBe(
22634                      'I am an HTMLstring with links! and other stuff');
22635                });
22636              </file>
22637            </example>
22638          */
22639         var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
22640           return {
22641             restrict: 'A',
22642             compile: function ngBindHtmlCompile(tElement, tAttrs) {
22643               var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
22644               var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
22645                 return (value || '').toString();
22646               });
22647               $compile.$$addBindingClass(tElement);
22648
22649               return function ngBindHtmlLink(scope, element, attr) {
22650                 $compile.$$addBindingInfo(element, attr.ngBindHtml);
22651
22652                 scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
22653                   // we re-evaluate the expr because we want a TrustedValueHolderType
22654                   // for $sce, not a string
22655                   element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
22656                 });
22657               };
22658             }
22659           };
22660         }];
22661
22662         /**
22663          * @ngdoc directive
22664          * @name ngChange
22665          *
22666          * @description
22667          * Evaluate the given expression when the user changes the input.
22668          * The expression is evaluated immediately, unlike the JavaScript onchange event
22669          * which only triggers at the end of a change (usually, when the user leaves the
22670          * form element or presses the return key).
22671          *
22672          * The `ngChange` expression is only evaluated when a change in the input value causes
22673          * a new value to be committed to the model.
22674          *
22675          * It will not be evaluated:
22676          * * if the value returned from the `$parsers` transformation pipeline has not changed
22677          * * if the input has continued to be invalid since the model will stay `null`
22678          * * if the model is changed programmatically and not by a change to the input value
22679          *
22680          *
22681          * Note, this directive requires `ngModel` to be present.
22682          *
22683          * @element input
22684          * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
22685          * in input value.
22686          *
22687          * @example
22688          * <example name="ngChange-directive" module="changeExample">
22689          *   <file name="index.html">
22690          *     <script>
22691          *       angular.module('changeExample', [])
22692          *         .controller('ExampleController', ['$scope', function($scope) {
22693          *           $scope.counter = 0;
22694          *           $scope.change = function() {
22695          *             $scope.counter++;
22696          *           };
22697          *         }]);
22698          *     </script>
22699          *     <div ng-controller="ExampleController">
22700          *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
22701          *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
22702          *       <label for="ng-change-example2">Confirmed</label><br />
22703          *       <tt>debug = {{confirmed}}</tt><br/>
22704          *       <tt>counter = {{counter}}</tt><br/>
22705          *     </div>
22706          *   </file>
22707          *   <file name="protractor.js" type="protractor">
22708          *     var counter = element(by.binding('counter'));
22709          *     var debug = element(by.binding('confirmed'));
22710          *
22711          *     it('should evaluate the expression if changing from view', function() {
22712          *       expect(counter.getText()).toContain('0');
22713          *
22714          *       element(by.id('ng-change-example1')).click();
22715          *
22716          *       expect(counter.getText()).toContain('1');
22717          *       expect(debug.getText()).toContain('true');
22718          *     });
22719          *
22720          *     it('should not evaluate the expression if changing from model', function() {
22721          *       element(by.id('ng-change-example2')).click();
22722
22723          *       expect(counter.getText()).toContain('0');
22724          *       expect(debug.getText()).toContain('true');
22725          *     });
22726          *   </file>
22727          * </example>
22728          */
22729         var ngChangeDirective = valueFn({
22730           restrict: 'A',
22731           require: 'ngModel',
22732           link: function(scope, element, attr, ctrl) {
22733             ctrl.$viewChangeListeners.push(function() {
22734               scope.$eval(attr.ngChange);
22735             });
22736           }
22737         });
22738
22739         function classDirective(name, selector) {
22740           name = 'ngClass' + name;
22741           return ['$animate', function($animate) {
22742             return {
22743               restrict: 'AC',
22744               link: function(scope, element, attr) {
22745                 var oldVal;
22746
22747                 scope.$watch(attr[name], ngClassWatchAction, true);
22748
22749                 attr.$observe('class', function(value) {
22750                   ngClassWatchAction(scope.$eval(attr[name]));
22751                 });
22752
22753
22754                 if (name !== 'ngClass') {
22755                   scope.$watch('$index', function($index, old$index) {
22756                     // jshint bitwise: false
22757                     var mod = $index & 1;
22758                     if (mod !== (old$index & 1)) {
22759                       var classes = arrayClasses(scope.$eval(attr[name]));
22760                       mod === selector ?
22761                         addClasses(classes) :
22762                         removeClasses(classes);
22763                     }
22764                   });
22765                 }
22766
22767                 function addClasses(classes) {
22768                   var newClasses = digestClassCounts(classes, 1);
22769                   attr.$addClass(newClasses);
22770                 }
22771
22772                 function removeClasses(classes) {
22773                   var newClasses = digestClassCounts(classes, -1);
22774                   attr.$removeClass(newClasses);
22775                 }
22776
22777                 function digestClassCounts(classes, count) {
22778                   // Use createMap() to prevent class assumptions involving property
22779                   // names in Object.prototype
22780                   var classCounts = element.data('$classCounts') || createMap();
22781                   var classesToUpdate = [];
22782                   forEach(classes, function(className) {
22783                     if (count > 0 || classCounts[className]) {
22784                       classCounts[className] = (classCounts[className] || 0) + count;
22785                       if (classCounts[className] === +(count > 0)) {
22786                         classesToUpdate.push(className);
22787                       }
22788                     }
22789                   });
22790                   element.data('$classCounts', classCounts);
22791                   return classesToUpdate.join(' ');
22792                 }
22793
22794                 function updateClasses(oldClasses, newClasses) {
22795                   var toAdd = arrayDifference(newClasses, oldClasses);
22796                   var toRemove = arrayDifference(oldClasses, newClasses);
22797                   toAdd = digestClassCounts(toAdd, 1);
22798                   toRemove = digestClassCounts(toRemove, -1);
22799                   if (toAdd && toAdd.length) {
22800                     $animate.addClass(element, toAdd);
22801                   }
22802                   if (toRemove && toRemove.length) {
22803                     $animate.removeClass(element, toRemove);
22804                   }
22805                 }
22806
22807                 function ngClassWatchAction(newVal) {
22808                   if (selector === true || scope.$index % 2 === selector) {
22809                     var newClasses = arrayClasses(newVal || []);
22810                     if (!oldVal) {
22811                       addClasses(newClasses);
22812                     } else if (!equals(newVal,oldVal)) {
22813                       var oldClasses = arrayClasses(oldVal);
22814                       updateClasses(oldClasses, newClasses);
22815                     }
22816                   }
22817                   oldVal = shallowCopy(newVal);
22818                 }
22819               }
22820             };
22821
22822             function arrayDifference(tokens1, tokens2) {
22823               var values = [];
22824
22825               outer:
22826               for (var i = 0; i < tokens1.length; i++) {
22827                 var token = tokens1[i];
22828                 for (var j = 0; j < tokens2.length; j++) {
22829                   if (token == tokens2[j]) continue outer;
22830                 }
22831                 values.push(token);
22832               }
22833               return values;
22834             }
22835
22836             function arrayClasses(classVal) {
22837               var classes = [];
22838               if (isArray(classVal)) {
22839                 forEach(classVal, function(v) {
22840                   classes = classes.concat(arrayClasses(v));
22841                 });
22842                 return classes;
22843               } else if (isString(classVal)) {
22844                 return classVal.split(' ');
22845               } else if (isObject(classVal)) {
22846                 forEach(classVal, function(v, k) {
22847                   if (v) {
22848                     classes = classes.concat(k.split(' '));
22849                   }
22850                 });
22851                 return classes;
22852               }
22853               return classVal;
22854             }
22855           }];
22856         }
22857
22858         /**
22859          * @ngdoc directive
22860          * @name ngClass
22861          * @restrict AC
22862          *
22863          * @description
22864          * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
22865          * an expression that represents all classes to be added.
22866          *
22867          * The directive operates in three different ways, depending on which of three types the expression
22868          * evaluates to:
22869          *
22870          * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
22871          * names.
22872          *
22873          * 2. If the expression evaluates to an object, then for each key-value pair of the
22874          * object with a truthy value the corresponding key is used as a class name.
22875          *
22876          * 3. If the expression evaluates to an array, each element of the array should either be a string as in
22877          * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
22878          * to give you more control over what CSS classes appear. See the code below for an example of this.
22879          *
22880          *
22881          * The directive won't add duplicate classes if a particular class was already set.
22882          *
22883          * When the expression changes, the previously added classes are removed and only then are the
22884          * new classes added.
22885          *
22886          * @animations
22887          * **add** - happens just before the class is applied to the elements
22888          *
22889          * **remove** - happens just before the class is removed from the element
22890          *
22891          * @element ANY
22892          * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
22893          *   of the evaluation can be a string representing space delimited class
22894          *   names, an array, or a map of class names to boolean values. In the case of a map, the
22895          *   names of the properties whose values are truthy will be added as css classes to the
22896          *   element.
22897          *
22898          * @example Example that demonstrates basic bindings via ngClass directive.
22899            <example>
22900              <file name="index.html">
22901                <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
22902                <label>
22903                   <input type="checkbox" ng-model="deleted">
22904                   deleted (apply "strike" class)
22905                </label><br>
22906                <label>
22907                   <input type="checkbox" ng-model="important">
22908                   important (apply "bold" class)
22909                </label><br>
22910                <label>
22911                   <input type="checkbox" ng-model="error">
22912                   error (apply "has-error" class)
22913                </label>
22914                <hr>
22915                <p ng-class="style">Using String Syntax</p>
22916                <input type="text" ng-model="style"
22917                       placeholder="Type: bold strike red" aria-label="Type: bold strike red">
22918                <hr>
22919                <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
22920                <input ng-model="style1"
22921                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
22922                <input ng-model="style2"
22923                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
22924                <input ng-model="style3"
22925                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
22926                <hr>
22927                <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
22928                <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
22929                <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
22930              </file>
22931              <file name="style.css">
22932                .strike {
22933                    text-decoration: line-through;
22934                }
22935                .bold {
22936                    font-weight: bold;
22937                }
22938                .red {
22939                    color: red;
22940                }
22941                .has-error {
22942                    color: red;
22943                    background-color: yellow;
22944                }
22945                .orange {
22946                    color: orange;
22947                }
22948              </file>
22949              <file name="protractor.js" type="protractor">
22950                var ps = element.all(by.css('p'));
22951
22952                it('should let you toggle the class', function() {
22953
22954                  expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
22955                  expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
22956
22957                  element(by.model('important')).click();
22958                  expect(ps.first().getAttribute('class')).toMatch(/bold/);
22959
22960                  element(by.model('error')).click();
22961                  expect(ps.first().getAttribute('class')).toMatch(/has-error/);
22962                });
22963
22964                it('should let you toggle string example', function() {
22965                  expect(ps.get(1).getAttribute('class')).toBe('');
22966                  element(by.model('style')).clear();
22967                  element(by.model('style')).sendKeys('red');
22968                  expect(ps.get(1).getAttribute('class')).toBe('red');
22969                });
22970
22971                it('array example should have 3 classes', function() {
22972                  expect(ps.get(2).getAttribute('class')).toBe('');
22973                  element(by.model('style1')).sendKeys('bold');
22974                  element(by.model('style2')).sendKeys('strike');
22975                  element(by.model('style3')).sendKeys('red');
22976                  expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
22977                });
22978
22979                it('array with map example should have 2 classes', function() {
22980                  expect(ps.last().getAttribute('class')).toBe('');
22981                  element(by.model('style4')).sendKeys('bold');
22982                  element(by.model('warning')).click();
22983                  expect(ps.last().getAttribute('class')).toBe('bold orange');
22984                });
22985              </file>
22986            </example>
22987
22988            ## Animations
22989
22990            The example below demonstrates how to perform animations using ngClass.
22991
22992            <example module="ngAnimate" deps="angular-animate.js" animations="true">
22993              <file name="index.html">
22994               <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
22995               <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
22996               <br>
22997               <span class="base-class" ng-class="myVar">Sample Text</span>
22998              </file>
22999              <file name="style.css">
23000                .base-class {
23001                  transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23002                }
23003
23004                .base-class.my-class {
23005                  color: red;
23006                  font-size:3em;
23007                }
23008              </file>
23009              <file name="protractor.js" type="protractor">
23010                it('should check ng-class', function() {
23011                  expect(element(by.css('.base-class')).getAttribute('class')).not.
23012                    toMatch(/my-class/);
23013
23014                  element(by.id('setbtn')).click();
23015
23016                  expect(element(by.css('.base-class')).getAttribute('class')).
23017                    toMatch(/my-class/);
23018
23019                  element(by.id('clearbtn')).click();
23020
23021                  expect(element(by.css('.base-class')).getAttribute('class')).not.
23022                    toMatch(/my-class/);
23023                });
23024              </file>
23025            </example>
23026
23027
23028            ## ngClass and pre-existing CSS3 Transitions/Animations
23029            The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
23030            Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
23031            any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
23032            to view the step by step details of {@link $animate#addClass $animate.addClass} and
23033            {@link $animate#removeClass $animate.removeClass}.
23034          */
23035         var ngClassDirective = classDirective('', true);
23036
23037         /**
23038          * @ngdoc directive
23039          * @name ngClassOdd
23040          * @restrict AC
23041          *
23042          * @description
23043          * The `ngClassOdd` and `ngClassEven` directives work exactly as
23044          * {@link ng.directive:ngClass ngClass}, except they work in
23045          * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23046          *
23047          * This directive can be applied only within the scope of an
23048          * {@link ng.directive:ngRepeat ngRepeat}.
23049          *
23050          * @element ANY
23051          * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
23052          *   of the evaluation can be a string representing space delimited class names or an array.
23053          *
23054          * @example
23055            <example>
23056              <file name="index.html">
23057                 <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23058                   <li ng-repeat="name in names">
23059                    <span ng-class-odd="'odd'" ng-class-even="'even'">
23060                      {{name}}
23061                    </span>
23062                   </li>
23063                 </ol>
23064              </file>
23065              <file name="style.css">
23066                .odd {
23067                  color: red;
23068                }
23069                .even {
23070                  color: blue;
23071                }
23072              </file>
23073              <file name="protractor.js" type="protractor">
23074                it('should check ng-class-odd and ng-class-even', function() {
23075                  expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23076                    toMatch(/odd/);
23077                  expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23078                    toMatch(/even/);
23079                });
23080              </file>
23081            </example>
23082          */
23083         var ngClassOddDirective = classDirective('Odd', 0);
23084
23085         /**
23086          * @ngdoc directive
23087          * @name ngClassEven
23088          * @restrict AC
23089          *
23090          * @description
23091          * The `ngClassOdd` and `ngClassEven` directives work exactly as
23092          * {@link ng.directive:ngClass ngClass}, except they work in
23093          * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23094          *
23095          * This directive can be applied only within the scope of an
23096          * {@link ng.directive:ngRepeat ngRepeat}.
23097          *
23098          * @element ANY
23099          * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
23100          *   result of the evaluation can be a string representing space delimited class names or an array.
23101          *
23102          * @example
23103            <example>
23104              <file name="index.html">
23105                 <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23106                   <li ng-repeat="name in names">
23107                    <span ng-class-odd="'odd'" ng-class-even="'even'">
23108                      {{name}} &nbsp; &nbsp; &nbsp;
23109                    </span>
23110                   </li>
23111                 </ol>
23112              </file>
23113              <file name="style.css">
23114                .odd {
23115                  color: red;
23116                }
23117                .even {
23118                  color: blue;
23119                }
23120              </file>
23121              <file name="protractor.js" type="protractor">
23122                it('should check ng-class-odd and ng-class-even', function() {
23123                  expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23124                    toMatch(/odd/);
23125                  expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23126                    toMatch(/even/);
23127                });
23128              </file>
23129            </example>
23130          */
23131         var ngClassEvenDirective = classDirective('Even', 1);
23132
23133         /**
23134          * @ngdoc directive
23135          * @name ngCloak
23136          * @restrict AC
23137          *
23138          * @description
23139          * The `ngCloak` directive is used to prevent the Angular html template from being briefly
23140          * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
23141          * directive to avoid the undesirable flicker effect caused by the html template display.
23142          *
23143          * The directive can be applied to the `<body>` element, but the preferred usage is to apply
23144          * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
23145          * of the browser view.
23146          *
23147          * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
23148          * `angular.min.js`.
23149          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
23150          *
23151          * ```css
23152          * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
23153          *   display: none !important;
23154          * }
23155          * ```
23156          *
23157          * When this css rule is loaded by the browser, all html elements (including their children) that
23158          * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
23159          * during the compilation of the template it deletes the `ngCloak` element attribute, making
23160          * the compiled element visible.
23161          *
23162          * For the best result, the `angular.js` script must be loaded in the head section of the html
23163          * document; alternatively, the css rule above must be included in the external stylesheet of the
23164          * application.
23165          *
23166          * @element ANY
23167          *
23168          * @example
23169            <example>
23170              <file name="index.html">
23171                 <div id="template1" ng-cloak>{{ 'hello' }}</div>
23172                 <div id="template2" class="ng-cloak">{{ 'world' }}</div>
23173              </file>
23174              <file name="protractor.js" type="protractor">
23175                it('should remove the template directive and css class', function() {
23176                  expect($('#template1').getAttribute('ng-cloak')).
23177                    toBeNull();
23178                  expect($('#template2').getAttribute('ng-cloak')).
23179                    toBeNull();
23180                });
23181              </file>
23182            </example>
23183          *
23184          */
23185         var ngCloakDirective = ngDirective({
23186           compile: function(element, attr) {
23187             attr.$set('ngCloak', undefined);
23188             element.removeClass('ng-cloak');
23189           }
23190         });
23191
23192         /**
23193          * @ngdoc directive
23194          * @name ngController
23195          *
23196          * @description
23197          * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
23198          * supports the principles behind the Model-View-Controller design pattern.
23199          *
23200          * MVC components in angular:
23201          *
23202          * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
23203          *   are accessed through bindings.
23204          * * View — The template (HTML with data bindings) that is rendered into the View.
23205          * * Controller — The `ngController` directive specifies a Controller class; the class contains business
23206          *   logic behind the application to decorate the scope with functions and values
23207          *
23208          * Note that you can also attach controllers to the DOM by declaring it in a route definition
23209          * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
23210          * again using `ng-controller` in the template itself.  This will cause the controller to be attached
23211          * and executed twice.
23212          *
23213          * @element ANY
23214          * @scope
23215          * @priority 500
23216          * @param {expression} ngController Name of a constructor function registered with the current
23217          * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
23218          * that on the current scope evaluates to a constructor function.
23219          *
23220          * The controller instance can be published into a scope property by specifying
23221          * `ng-controller="as propertyName"`.
23222          *
23223          * If the current `$controllerProvider` is configured to use globals (via
23224          * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
23225          * also be the name of a globally accessible constructor function (not recommended).
23226          *
23227          * @example
23228          * Here is a simple form for editing user contact information. Adding, removing, clearing, and
23229          * greeting are methods declared on the controller (see source tab). These methods can
23230          * easily be called from the angular markup. Any changes to the data are automatically reflected
23231          * in the View without the need for a manual update.
23232          *
23233          * Two different declaration styles are included below:
23234          *
23235          * * one binds methods and properties directly onto the controller using `this`:
23236          * `ng-controller="SettingsController1 as settings"`
23237          * * one injects `$scope` into the controller:
23238          * `ng-controller="SettingsController2"`
23239          *
23240          * The second option is more common in the Angular community, and is generally used in boilerplates
23241          * and in this guide. However, there are advantages to binding properties directly to the controller
23242          * and avoiding scope.
23243          *
23244          * * Using `controller as` makes it obvious which controller you are accessing in the template when
23245          * multiple controllers apply to an element.
23246          * * If you are writing your controllers as classes you have easier access to the properties and
23247          * methods, which will appear on the scope, from inside the controller code.
23248          * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
23249          * inheritance masking primitives.
23250          *
23251          * This example demonstrates the `controller as` syntax.
23252          *
23253          * <example name="ngControllerAs" module="controllerAsExample">
23254          *   <file name="index.html">
23255          *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
23256          *      <label>Name: <input type="text" ng-model="settings.name"/></label>
23257          *      <button ng-click="settings.greet()">greet</button><br/>
23258          *      Contact:
23259          *      <ul>
23260          *        <li ng-repeat="contact in settings.contacts">
23261          *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
23262          *             <option>phone</option>
23263          *             <option>email</option>
23264          *          </select>
23265          *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
23266          *          <button ng-click="settings.clearContact(contact)">clear</button>
23267          *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
23268          *        </li>
23269          *        <li><button ng-click="settings.addContact()">add</button></li>
23270          *     </ul>
23271          *    </div>
23272          *   </file>
23273          *   <file name="app.js">
23274          *    angular.module('controllerAsExample', [])
23275          *      .controller('SettingsController1', SettingsController1);
23276          *
23277          *    function SettingsController1() {
23278          *      this.name = "John Smith";
23279          *      this.contacts = [
23280          *        {type: 'phone', value: '408 555 1212'},
23281          *        {type: 'email', value: 'john.smith@example.org'} ];
23282          *    }
23283          *
23284          *    SettingsController1.prototype.greet = function() {
23285          *      alert(this.name);
23286          *    };
23287          *
23288          *    SettingsController1.prototype.addContact = function() {
23289          *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
23290          *    };
23291          *
23292          *    SettingsController1.prototype.removeContact = function(contactToRemove) {
23293          *     var index = this.contacts.indexOf(contactToRemove);
23294          *      this.contacts.splice(index, 1);
23295          *    };
23296          *
23297          *    SettingsController1.prototype.clearContact = function(contact) {
23298          *      contact.type = 'phone';
23299          *      contact.value = '';
23300          *    };
23301          *   </file>
23302          *   <file name="protractor.js" type="protractor">
23303          *     it('should check controller as', function() {
23304          *       var container = element(by.id('ctrl-as-exmpl'));
23305          *         expect(container.element(by.model('settings.name'))
23306          *           .getAttribute('value')).toBe('John Smith');
23307          *
23308          *       var firstRepeat =
23309          *           container.element(by.repeater('contact in settings.contacts').row(0));
23310          *       var secondRepeat =
23311          *           container.element(by.repeater('contact in settings.contacts').row(1));
23312          *
23313          *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23314          *           .toBe('408 555 1212');
23315          *
23316          *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23317          *           .toBe('john.smith@example.org');
23318          *
23319          *       firstRepeat.element(by.buttonText('clear')).click();
23320          *
23321          *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23322          *           .toBe('');
23323          *
23324          *       container.element(by.buttonText('add')).click();
23325          *
23326          *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
23327          *           .element(by.model('contact.value'))
23328          *           .getAttribute('value'))
23329          *           .toBe('yourname@example.org');
23330          *     });
23331          *   </file>
23332          * </example>
23333          *
23334          * This example demonstrates the "attach to `$scope`" style of controller.
23335          *
23336          * <example name="ngController" module="controllerExample">
23337          *  <file name="index.html">
23338          *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
23339          *     <label>Name: <input type="text" ng-model="name"/></label>
23340          *     <button ng-click="greet()">greet</button><br/>
23341          *     Contact:
23342          *     <ul>
23343          *       <li ng-repeat="contact in contacts">
23344          *         <select ng-model="contact.type" id="select_{{$index}}">
23345          *            <option>phone</option>
23346          *            <option>email</option>
23347          *         </select>
23348          *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
23349          *         <button ng-click="clearContact(contact)">clear</button>
23350          *         <button ng-click="removeContact(contact)">X</button>
23351          *       </li>
23352          *       <li>[ <button ng-click="addContact()">add</button> ]</li>
23353          *    </ul>
23354          *   </div>
23355          *  </file>
23356          *  <file name="app.js">
23357          *   angular.module('controllerExample', [])
23358          *     .controller('SettingsController2', ['$scope', SettingsController2]);
23359          *
23360          *   function SettingsController2($scope) {
23361          *     $scope.name = "John Smith";
23362          *     $scope.contacts = [
23363          *       {type:'phone', value:'408 555 1212'},
23364          *       {type:'email', value:'john.smith@example.org'} ];
23365          *
23366          *     $scope.greet = function() {
23367          *       alert($scope.name);
23368          *     };
23369          *
23370          *     $scope.addContact = function() {
23371          *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
23372          *     };
23373          *
23374          *     $scope.removeContact = function(contactToRemove) {
23375          *       var index = $scope.contacts.indexOf(contactToRemove);
23376          *       $scope.contacts.splice(index, 1);
23377          *     };
23378          *
23379          *     $scope.clearContact = function(contact) {
23380          *       contact.type = 'phone';
23381          *       contact.value = '';
23382          *     };
23383          *   }
23384          *  </file>
23385          *  <file name="protractor.js" type="protractor">
23386          *    it('should check controller', function() {
23387          *      var container = element(by.id('ctrl-exmpl'));
23388          *
23389          *      expect(container.element(by.model('name'))
23390          *          .getAttribute('value')).toBe('John Smith');
23391          *
23392          *      var firstRepeat =
23393          *          container.element(by.repeater('contact in contacts').row(0));
23394          *      var secondRepeat =
23395          *          container.element(by.repeater('contact in contacts').row(1));
23396          *
23397          *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23398          *          .toBe('408 555 1212');
23399          *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23400          *          .toBe('john.smith@example.org');
23401          *
23402          *      firstRepeat.element(by.buttonText('clear')).click();
23403          *
23404          *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23405          *          .toBe('');
23406          *
23407          *      container.element(by.buttonText('add')).click();
23408          *
23409          *      expect(container.element(by.repeater('contact in contacts').row(2))
23410          *          .element(by.model('contact.value'))
23411          *          .getAttribute('value'))
23412          *          .toBe('yourname@example.org');
23413          *    });
23414          *  </file>
23415          *</example>
23416
23417          */
23418         var ngControllerDirective = [function() {
23419           return {
23420             restrict: 'A',
23421             scope: true,
23422             controller: '@',
23423             priority: 500
23424           };
23425         }];
23426
23427         /**
23428          * @ngdoc directive
23429          * @name ngCsp
23430          *
23431          * @element html
23432          * @description
23433          *
23434          * Angular has some features that can break certain
23435          * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
23436          *
23437          * If you intend to implement these rules then you must tell Angular not to use these features.
23438          *
23439          * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
23440          *
23441          *
23442          * The following rules affect Angular:
23443          *
23444          * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
23445          * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
23446          * increase in the speed of evaluating Angular expressions.
23447          *
23448          * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
23449          * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
23450          * To make these directives work when a CSP rule is blocking inline styles, you must link to the
23451          * `angular-csp.css` in your HTML manually.
23452          *
23453          * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
23454          * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
23455          * however, triggers a CSP error to be logged in the console:
23456          *
23457          * ```
23458          * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
23459          * script in the following Content Security Policy directive: "default-src 'self'". Note that
23460          * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
23461          * ```
23462          *
23463          * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
23464          * directive on an element of the HTML document that appears before the `<script>` tag that loads
23465          * the `angular.js` file.
23466          *
23467          * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
23468          *
23469          * You can specify which of the CSP related Angular features should be deactivated by providing
23470          * a value for the `ng-csp` attribute. The options are as follows:
23471          *
23472          * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
23473          *
23474          * * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
23475          *
23476          * You can use these values in the following combinations:
23477          *
23478          *
23479          * * No declaration means that Angular will assume that you can do inline styles, but it will do
23480          * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous versions
23481          * of Angular.
23482          *
23483          * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
23484          * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous versions
23485          * of Angular.
23486          *
23487          * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can inject
23488          * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
23489          *
23490          * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
23491          * run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
23492          *
23493          * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
23494          * styles nor use eval, which is the same as an empty: ng-csp.
23495          * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
23496          *
23497          * @example
23498          * This example shows how to apply the `ngCsp` directive to the `html` tag.
23499            ```html
23500              <!doctype html>
23501              <html ng-app ng-csp>
23502              ...
23503              ...
23504              </html>
23505            ```
23506           * @example
23507               // Note: the suffix `.csp` in the example name triggers
23508               // csp mode in our http server!
23509               <example name="example.csp" module="cspExample" ng-csp="true">
23510                 <file name="index.html">
23511                   <div ng-controller="MainController as ctrl">
23512                     <div>
23513                       <button ng-click="ctrl.inc()" id="inc">Increment</button>
23514                       <span id="counter">
23515                         {{ctrl.counter}}
23516                       </span>
23517                     </div>
23518
23519                     <div>
23520                       <button ng-click="ctrl.evil()" id="evil">Evil</button>
23521                       <span id="evilError">
23522                         {{ctrl.evilError}}
23523                       </span>
23524                     </div>
23525                   </div>
23526                 </file>
23527                 <file name="script.js">
23528                    angular.module('cspExample', [])
23529                      .controller('MainController', function() {
23530                         this.counter = 0;
23531                         this.inc = function() {
23532                           this.counter++;
23533                         };
23534                         this.evil = function() {
23535                           // jshint evil:true
23536                           try {
23537                             eval('1+2');
23538                           } catch (e) {
23539                             this.evilError = e.message;
23540                           }
23541                         };
23542                       });
23543                 </file>
23544                 <file name="protractor.js" type="protractor">
23545                   var util, webdriver;
23546
23547                   var incBtn = element(by.id('inc'));
23548                   var counter = element(by.id('counter'));
23549                   var evilBtn = element(by.id('evil'));
23550                   var evilError = element(by.id('evilError'));
23551
23552                   function getAndClearSevereErrors() {
23553                     return browser.manage().logs().get('browser').then(function(browserLog) {
23554                       return browserLog.filter(function(logEntry) {
23555                         return logEntry.level.value > webdriver.logging.Level.WARNING.value;
23556                       });
23557                     });
23558                   }
23559
23560                   function clearErrors() {
23561                     getAndClearSevereErrors();
23562                   }
23563
23564                   function expectNoErrors() {
23565                     getAndClearSevereErrors().then(function(filteredLog) {
23566                       expect(filteredLog.length).toEqual(0);
23567                       if (filteredLog.length) {
23568                         console.log('browser console errors: ' + util.inspect(filteredLog));
23569                       }
23570                     });
23571                   }
23572
23573                   function expectError(regex) {
23574                     getAndClearSevereErrors().then(function(filteredLog) {
23575                       var found = false;
23576                       filteredLog.forEach(function(log) {
23577                         if (log.message.match(regex)) {
23578                           found = true;
23579                         }
23580                       });
23581                       if (!found) {
23582                         throw new Error('expected an error that matches ' + regex);
23583                       }
23584                     });
23585                   }
23586
23587                   beforeEach(function() {
23588                     util = require('util');
23589                     webdriver = require('protractor/node_modules/selenium-webdriver');
23590                   });
23591
23592                   // For now, we only test on Chrome,
23593                   // as Safari does not load the page with Protractor's injected scripts,
23594                   // and Firefox webdriver always disables content security policy (#6358)
23595                   if (browser.params.browser !== 'chrome') {
23596                     return;
23597                   }
23598
23599                   it('should not report errors when the page is loaded', function() {
23600                     // clear errors so we are not dependent on previous tests
23601                     clearErrors();
23602                     // Need to reload the page as the page is already loaded when
23603                     // we come here
23604                     browser.driver.getCurrentUrl().then(function(url) {
23605                       browser.get(url);
23606                     });
23607                     expectNoErrors();
23608                   });
23609
23610                   it('should evaluate expressions', function() {
23611                     expect(counter.getText()).toEqual('0');
23612                     incBtn.click();
23613                     expect(counter.getText()).toEqual('1');
23614                     expectNoErrors();
23615                   });
23616
23617                   it('should throw and report an error when using "eval"', function() {
23618                     evilBtn.click();
23619                     expect(evilError.getText()).toMatch(/Content Security Policy/);
23620                     expectError(/Content Security Policy/);
23621                   });
23622                 </file>
23623               </example>
23624           */
23625
23626         // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
23627         // bootstrap the system (before $parse is instantiated), for this reason we just have
23628         // the csp() fn that looks for the `ng-csp` attribute anywhere in the current doc
23629
23630         /**
23631          * @ngdoc directive
23632          * @name ngClick
23633          *
23634          * @description
23635          * The ngClick directive allows you to specify custom behavior when
23636          * an element is clicked.
23637          *
23638          * @element ANY
23639          * @priority 0
23640          * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
23641          * click. ({@link guide/expression#-event- Event object is available as `$event`})
23642          *
23643          * @example
23644            <example>
23645              <file name="index.html">
23646               <button ng-click="count = count + 1" ng-init="count=0">
23647                 Increment
23648               </button>
23649               <span>
23650                 count: {{count}}
23651               </span>
23652              </file>
23653              <file name="protractor.js" type="protractor">
23654                it('should check ng-click', function() {
23655                  expect(element(by.binding('count')).getText()).toMatch('0');
23656                  element(by.css('button')).click();
23657                  expect(element(by.binding('count')).getText()).toMatch('1');
23658                });
23659              </file>
23660            </example>
23661          */
23662         /*
23663          * A collection of directives that allows creation of custom event handlers that are defined as
23664          * angular expressions and are compiled and executed within the current scope.
23665          */
23666         var ngEventDirectives = {};
23667
23668         // For events that might fire synchronously during DOM manipulation
23669         // we need to execute their event handlers asynchronously using $evalAsync,
23670         // so that they are not executed in an inconsistent state.
23671         var forceAsyncEvents = {
23672           'blur': true,
23673           'focus': true
23674         };
23675         forEach(
23676           'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
23677           function(eventName) {
23678             var directiveName = directiveNormalize('ng-' + eventName);
23679             ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
23680               return {
23681                 restrict: 'A',
23682                 compile: function($element, attr) {
23683                   // We expose the powerful $event object on the scope that provides access to the Window,
23684                   // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
23685                   // checks at the cost of speed since event handler expressions are not executed as
23686                   // frequently as regular change detection.
23687                   var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
23688                   return function ngEventHandler(scope, element) {
23689                     element.on(eventName, function(event) {
23690                       var callback = function() {
23691                         fn(scope, {$event:event});
23692                       };
23693                       if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
23694                         scope.$evalAsync(callback);
23695                       } else {
23696                         scope.$apply(callback);
23697                       }
23698                     });
23699                   };
23700                 }
23701               };
23702             }];
23703           }
23704         );
23705
23706         /**
23707          * @ngdoc directive
23708          * @name ngDblclick
23709          *
23710          * @description
23711          * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
23712          *
23713          * @element ANY
23714          * @priority 0
23715          * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
23716          * a dblclick. (The Event object is available as `$event`)
23717          *
23718          * @example
23719            <example>
23720              <file name="index.html">
23721               <button ng-dblclick="count = count + 1" ng-init="count=0">
23722                 Increment (on double click)
23723               </button>
23724               count: {{count}}
23725              </file>
23726            </example>
23727          */
23728
23729
23730         /**
23731          * @ngdoc directive
23732          * @name ngMousedown
23733          *
23734          * @description
23735          * The ngMousedown directive allows you to specify custom behavior on mousedown event.
23736          *
23737          * @element ANY
23738          * @priority 0
23739          * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
23740          * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
23741          *
23742          * @example
23743            <example>
23744              <file name="index.html">
23745               <button ng-mousedown="count = count + 1" ng-init="count=0">
23746                 Increment (on mouse down)
23747               </button>
23748               count: {{count}}
23749              </file>
23750            </example>
23751          */
23752
23753
23754         /**
23755          * @ngdoc directive
23756          * @name ngMouseup
23757          *
23758          * @description
23759          * Specify custom behavior on mouseup event.
23760          *
23761          * @element ANY
23762          * @priority 0
23763          * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
23764          * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
23765          *
23766          * @example
23767            <example>
23768              <file name="index.html">
23769               <button ng-mouseup="count = count + 1" ng-init="count=0">
23770                 Increment (on mouse up)
23771               </button>
23772               count: {{count}}
23773              </file>
23774            </example>
23775          */
23776
23777         /**
23778          * @ngdoc directive
23779          * @name ngMouseover
23780          *
23781          * @description
23782          * Specify custom behavior on mouseover event.
23783          *
23784          * @element ANY
23785          * @priority 0
23786          * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
23787          * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
23788          *
23789          * @example
23790            <example>
23791              <file name="index.html">
23792               <button ng-mouseover="count = count + 1" ng-init="count=0">
23793                 Increment (when mouse is over)
23794               </button>
23795               count: {{count}}
23796              </file>
23797            </example>
23798          */
23799
23800
23801         /**
23802          * @ngdoc directive
23803          * @name ngMouseenter
23804          *
23805          * @description
23806          * Specify custom behavior on mouseenter event.
23807          *
23808          * @element ANY
23809          * @priority 0
23810          * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
23811          * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
23812          *
23813          * @example
23814            <example>
23815              <file name="index.html">
23816               <button ng-mouseenter="count = count + 1" ng-init="count=0">
23817                 Increment (when mouse enters)
23818               </button>
23819               count: {{count}}
23820              </file>
23821            </example>
23822          */
23823
23824
23825         /**
23826          * @ngdoc directive
23827          * @name ngMouseleave
23828          *
23829          * @description
23830          * Specify custom behavior on mouseleave event.
23831          *
23832          * @element ANY
23833          * @priority 0
23834          * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
23835          * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
23836          *
23837          * @example
23838            <example>
23839              <file name="index.html">
23840               <button ng-mouseleave="count = count + 1" ng-init="count=0">
23841                 Increment (when mouse leaves)
23842               </button>
23843               count: {{count}}
23844              </file>
23845            </example>
23846          */
23847
23848
23849         /**
23850          * @ngdoc directive
23851          * @name ngMousemove
23852          *
23853          * @description
23854          * Specify custom behavior on mousemove event.
23855          *
23856          * @element ANY
23857          * @priority 0
23858          * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
23859          * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
23860          *
23861          * @example
23862            <example>
23863              <file name="index.html">
23864               <button ng-mousemove="count = count + 1" ng-init="count=0">
23865                 Increment (when mouse moves)
23866               </button>
23867               count: {{count}}
23868              </file>
23869            </example>
23870          */
23871
23872
23873         /**
23874          * @ngdoc directive
23875          * @name ngKeydown
23876          *
23877          * @description
23878          * Specify custom behavior on keydown event.
23879          *
23880          * @element ANY
23881          * @priority 0
23882          * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
23883          * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23884          *
23885          * @example
23886            <example>
23887              <file name="index.html">
23888               <input ng-keydown="count = count + 1" ng-init="count=0">
23889               key down count: {{count}}
23890              </file>
23891            </example>
23892          */
23893
23894
23895         /**
23896          * @ngdoc directive
23897          * @name ngKeyup
23898          *
23899          * @description
23900          * Specify custom behavior on keyup event.
23901          *
23902          * @element ANY
23903          * @priority 0
23904          * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
23905          * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23906          *
23907          * @example
23908            <example>
23909              <file name="index.html">
23910                <p>Typing in the input box below updates the key count</p>
23911                <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
23912
23913                <p>Typing in the input box below updates the keycode</p>
23914                <input ng-keyup="event=$event">
23915                <p>event keyCode: {{ event.keyCode }}</p>
23916                <p>event altKey: {{ event.altKey }}</p>
23917              </file>
23918            </example>
23919          */
23920
23921
23922         /**
23923          * @ngdoc directive
23924          * @name ngKeypress
23925          *
23926          * @description
23927          * Specify custom behavior on keypress event.
23928          *
23929          * @element ANY
23930          * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
23931          * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
23932          * and can be interrogated for keyCode, altKey, etc.)
23933          *
23934          * @example
23935            <example>
23936              <file name="index.html">
23937               <input ng-keypress="count = count + 1" ng-init="count=0">
23938               key press count: {{count}}
23939              </file>
23940            </example>
23941          */
23942
23943
23944         /**
23945          * @ngdoc directive
23946          * @name ngSubmit
23947          *
23948          * @description
23949          * Enables binding angular expressions to onsubmit events.
23950          *
23951          * Additionally it prevents the default action (which for form means sending the request to the
23952          * server and reloading the current page), but only if the form does not contain `action`,
23953          * `data-action`, or `x-action` attributes.
23954          *
23955          * <div class="alert alert-warning">
23956          * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
23957          * `ngSubmit` handlers together. See the
23958          * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
23959          * for a detailed discussion of when `ngSubmit` may be triggered.
23960          * </div>
23961          *
23962          * @element form
23963          * @priority 0
23964          * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
23965          * ({@link guide/expression#-event- Event object is available as `$event`})
23966          *
23967          * @example
23968            <example module="submitExample">
23969              <file name="index.html">
23970               <script>
23971                 angular.module('submitExample', [])
23972                   .controller('ExampleController', ['$scope', function($scope) {
23973                     $scope.list = [];
23974                     $scope.text = 'hello';
23975                     $scope.submit = function() {
23976                       if ($scope.text) {
23977                         $scope.list.push(this.text);
23978                         $scope.text = '';
23979                       }
23980                     };
23981                   }]);
23982               </script>
23983               <form ng-submit="submit()" ng-controller="ExampleController">
23984                 Enter text and hit enter:
23985                 <input type="text" ng-model="text" name="text" />
23986                 <input type="submit" id="submit" value="Submit" />
23987                 <pre>list={{list}}</pre>
23988               </form>
23989              </file>
23990              <file name="protractor.js" type="protractor">
23991                it('should check ng-submit', function() {
23992                  expect(element(by.binding('list')).getText()).toBe('list=[]');
23993                  element(by.css('#submit')).click();
23994                  expect(element(by.binding('list')).getText()).toContain('hello');
23995                  expect(element(by.model('text')).getAttribute('value')).toBe('');
23996                });
23997                it('should ignore empty strings', function() {
23998                  expect(element(by.binding('list')).getText()).toBe('list=[]');
23999                  element(by.css('#submit')).click();
24000                  element(by.css('#submit')).click();
24001                  expect(element(by.binding('list')).getText()).toContain('hello');
24002                 });
24003              </file>
24004            </example>
24005          */
24006
24007         /**
24008          * @ngdoc directive
24009          * @name ngFocus
24010          *
24011          * @description
24012          * Specify custom behavior on focus event.
24013          *
24014          * Note: As the `focus` event is executed synchronously when calling `input.focus()`
24015          * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
24016          * during an `$apply` to ensure a consistent state.
24017          *
24018          * @element window, input, select, textarea, a
24019          * @priority 0
24020          * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
24021          * focus. ({@link guide/expression#-event- Event object is available as `$event`})
24022          *
24023          * @example
24024          * See {@link ng.directive:ngClick ngClick}
24025          */
24026
24027         /**
24028          * @ngdoc directive
24029          * @name ngBlur
24030          *
24031          * @description
24032          * Specify custom behavior on blur event.
24033          *
24034          * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
24035          * an element has lost focus.
24036          *
24037          * Note: As the `blur` event is executed synchronously also during DOM manipulations
24038          * (e.g. removing a focussed input),
24039          * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
24040          * during an `$apply` to ensure a consistent state.
24041          *
24042          * @element window, input, select, textarea, a
24043          * @priority 0
24044          * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
24045          * blur. ({@link guide/expression#-event- Event object is available as `$event`})
24046          *
24047          * @example
24048          * See {@link ng.directive:ngClick ngClick}
24049          */
24050
24051         /**
24052          * @ngdoc directive
24053          * @name ngCopy
24054          *
24055          * @description
24056          * Specify custom behavior on copy event.
24057          *
24058          * @element window, input, select, textarea, a
24059          * @priority 0
24060          * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
24061          * copy. ({@link guide/expression#-event- Event object is available as `$event`})
24062          *
24063          * @example
24064            <example>
24065              <file name="index.html">
24066               <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
24067               copied: {{copied}}
24068              </file>
24069            </example>
24070          */
24071
24072         /**
24073          * @ngdoc directive
24074          * @name ngCut
24075          *
24076          * @description
24077          * Specify custom behavior on cut event.
24078          *
24079          * @element window, input, select, textarea, a
24080          * @priority 0
24081          * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
24082          * cut. ({@link guide/expression#-event- Event object is available as `$event`})
24083          *
24084          * @example
24085            <example>
24086              <file name="index.html">
24087               <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
24088               cut: {{cut}}
24089              </file>
24090            </example>
24091          */
24092
24093         /**
24094          * @ngdoc directive
24095          * @name ngPaste
24096          *
24097          * @description
24098          * Specify custom behavior on paste event.
24099          *
24100          * @element window, input, select, textarea, a
24101          * @priority 0
24102          * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
24103          * paste. ({@link guide/expression#-event- Event object is available as `$event`})
24104          *
24105          * @example
24106            <example>
24107              <file name="index.html">
24108               <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
24109               pasted: {{paste}}
24110              </file>
24111            </example>
24112          */
24113
24114         /**
24115          * @ngdoc directive
24116          * @name ngIf
24117          * @restrict A
24118          * @multiElement
24119          *
24120          * @description
24121          * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
24122          * {expression}. If the expression assigned to `ngIf` evaluates to a false
24123          * value then the element is removed from the DOM, otherwise a clone of the
24124          * element is reinserted into the DOM.
24125          *
24126          * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
24127          * element in the DOM rather than changing its visibility via the `display` css property.  A common
24128          * case when this difference is significant is when using css selectors that rely on an element's
24129          * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
24130          *
24131          * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
24132          * is created when the element is restored.  The scope created within `ngIf` inherits from
24133          * its parent scope using
24134          * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
24135          * An important implication of this is if `ngModel` is used within `ngIf` to bind to
24136          * a javascript primitive defined in the parent scope. In this case any modifications made to the
24137          * variable within the child scope will override (hide) the value in the parent scope.
24138          *
24139          * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
24140          * is if an element's class attribute is directly modified after it's compiled, using something like
24141          * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
24142          * the added class will be lost because the original compiled state is used to regenerate the element.
24143          *
24144          * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
24145          * and `leave` effects.
24146          *
24147          * @animations
24148          * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
24149          * leave - happens just before the `ngIf` contents are removed from the DOM
24150          *
24151          * @element ANY
24152          * @scope
24153          * @priority 600
24154          * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
24155          *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
24156          *     element is added to the DOM tree.
24157          *
24158          * @example
24159           <example module="ngAnimate" deps="angular-animate.js" animations="true">
24160             <file name="index.html">
24161               <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
24162               Show when checked:
24163               <span ng-if="checked" class="animate-if">
24164                 This is removed when the checkbox is unchecked.
24165               </span>
24166             </file>
24167             <file name="animations.css">
24168               .animate-if {
24169                 background:white;
24170                 border:1px solid black;
24171                 padding:10px;
24172               }
24173
24174               .animate-if.ng-enter, .animate-if.ng-leave {
24175                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24176               }
24177
24178               .animate-if.ng-enter,
24179               .animate-if.ng-leave.ng-leave-active {
24180                 opacity:0;
24181               }
24182
24183               .animate-if.ng-leave,
24184               .animate-if.ng-enter.ng-enter-active {
24185                 opacity:1;
24186               }
24187             </file>
24188           </example>
24189          */
24190         var ngIfDirective = ['$animate', function($animate) {
24191           return {
24192             multiElement: true,
24193             transclude: 'element',
24194             priority: 600,
24195             terminal: true,
24196             restrict: 'A',
24197             $$tlb: true,
24198             link: function($scope, $element, $attr, ctrl, $transclude) {
24199                 var block, childScope, previousElements;
24200                 $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
24201
24202                   if (value) {
24203                     if (!childScope) {
24204                       $transclude(function(clone, newScope) {
24205                         childScope = newScope;
24206                         clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
24207                         // Note: We only need the first/last node of the cloned nodes.
24208                         // However, we need to keep the reference to the jqlite wrapper as it might be changed later
24209                         // by a directive with templateUrl when its template arrives.
24210                         block = {
24211                           clone: clone
24212                         };
24213                         $animate.enter(clone, $element.parent(), $element);
24214                       });
24215                     }
24216                   } else {
24217                     if (previousElements) {
24218                       previousElements.remove();
24219                       previousElements = null;
24220                     }
24221                     if (childScope) {
24222                       childScope.$destroy();
24223                       childScope = null;
24224                     }
24225                     if (block) {
24226                       previousElements = getBlockNodes(block.clone);
24227                       $animate.leave(previousElements).then(function() {
24228                         previousElements = null;
24229                       });
24230                       block = null;
24231                     }
24232                   }
24233                 });
24234             }
24235           };
24236         }];
24237
24238         /**
24239          * @ngdoc directive
24240          * @name ngInclude
24241          * @restrict ECA
24242          *
24243          * @description
24244          * Fetches, compiles and includes an external HTML fragment.
24245          *
24246          * By default, the template URL is restricted to the same domain and protocol as the
24247          * application document. This is done by calling {@link $sce#getTrustedResourceUrl
24248          * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
24249          * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
24250          * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
24251          * ng.$sce Strict Contextual Escaping}.
24252          *
24253          * In addition, the browser's
24254          * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
24255          * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
24256          * policy may further restrict whether the template is successfully loaded.
24257          * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
24258          * access on some browsers.
24259          *
24260          * @animations
24261          * enter - animation is used to bring new content into the browser.
24262          * leave - animation is used to animate existing content away.
24263          *
24264          * The enter and leave animation occur concurrently.
24265          *
24266          * @scope
24267          * @priority 400
24268          *
24269          * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
24270          *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
24271          * @param {string=} onload Expression to evaluate when a new partial is loaded.
24272          *                  <div class="alert alert-warning">
24273          *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
24274          *                  a function with the name on the window element, which will usually throw a
24275          *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
24276          *                  different form that {@link guide/directive#normalization matches} `onload`.
24277          *                  </div>
24278            *
24279          * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
24280          *                  $anchorScroll} to scroll the viewport after the content is loaded.
24281          *
24282          *                  - If the attribute is not set, disable scrolling.
24283          *                  - If the attribute is set without value, enable scrolling.
24284          *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
24285          *
24286          * @example
24287           <example module="includeExample" deps="angular-animate.js" animations="true">
24288             <file name="index.html">
24289              <div ng-controller="ExampleController">
24290                <select ng-model="template" ng-options="t.name for t in templates">
24291                 <option value="">(blank)</option>
24292                </select>
24293                url of the template: <code>{{template.url}}</code>
24294                <hr/>
24295                <div class="slide-animate-container">
24296                  <div class="slide-animate" ng-include="template.url"></div>
24297                </div>
24298              </div>
24299             </file>
24300             <file name="script.js">
24301               angular.module('includeExample', ['ngAnimate'])
24302                 .controller('ExampleController', ['$scope', function($scope) {
24303                   $scope.templates =
24304                     [ { name: 'template1.html', url: 'template1.html'},
24305                       { name: 'template2.html', url: 'template2.html'} ];
24306                   $scope.template = $scope.templates[0];
24307                 }]);
24308              </file>
24309             <file name="template1.html">
24310               Content of template1.html
24311             </file>
24312             <file name="template2.html">
24313               Content of template2.html
24314             </file>
24315             <file name="animations.css">
24316               .slide-animate-container {
24317                 position:relative;
24318                 background:white;
24319                 border:1px solid black;
24320                 height:40px;
24321                 overflow:hidden;
24322               }
24323
24324               .slide-animate {
24325                 padding:10px;
24326               }
24327
24328               .slide-animate.ng-enter, .slide-animate.ng-leave {
24329                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24330
24331                 position:absolute;
24332                 top:0;
24333                 left:0;
24334                 right:0;
24335                 bottom:0;
24336                 display:block;
24337                 padding:10px;
24338               }
24339
24340               .slide-animate.ng-enter {
24341                 top:-50px;
24342               }
24343               .slide-animate.ng-enter.ng-enter-active {
24344                 top:0;
24345               }
24346
24347               .slide-animate.ng-leave {
24348                 top:0;
24349               }
24350               .slide-animate.ng-leave.ng-leave-active {
24351                 top:50px;
24352               }
24353             </file>
24354             <file name="protractor.js" type="protractor">
24355               var templateSelect = element(by.model('template'));
24356               var includeElem = element(by.css('[ng-include]'));
24357
24358               it('should load template1.html', function() {
24359                 expect(includeElem.getText()).toMatch(/Content of template1.html/);
24360               });
24361
24362               it('should load template2.html', function() {
24363                 if (browser.params.browser == 'firefox') {
24364                   // Firefox can't handle using selects
24365                   // See https://github.com/angular/protractor/issues/480
24366                   return;
24367                 }
24368                 templateSelect.click();
24369                 templateSelect.all(by.css('option')).get(2).click();
24370                 expect(includeElem.getText()).toMatch(/Content of template2.html/);
24371               });
24372
24373               it('should change to blank', function() {
24374                 if (browser.params.browser == 'firefox') {
24375                   // Firefox can't handle using selects
24376                   return;
24377                 }
24378                 templateSelect.click();
24379                 templateSelect.all(by.css('option')).get(0).click();
24380                 expect(includeElem.isPresent()).toBe(false);
24381               });
24382             </file>
24383           </example>
24384          */
24385
24386
24387         /**
24388          * @ngdoc event
24389          * @name ngInclude#$includeContentRequested
24390          * @eventType emit on the scope ngInclude was declared in
24391          * @description
24392          * Emitted every time the ngInclude content is requested.
24393          *
24394          * @param {Object} angularEvent Synthetic event object.
24395          * @param {String} src URL of content to load.
24396          */
24397
24398
24399         /**
24400          * @ngdoc event
24401          * @name ngInclude#$includeContentLoaded
24402          * @eventType emit on the current ngInclude scope
24403          * @description
24404          * Emitted every time the ngInclude content is reloaded.
24405          *
24406          * @param {Object} angularEvent Synthetic event object.
24407          * @param {String} src URL of content to load.
24408          */
24409
24410
24411         /**
24412          * @ngdoc event
24413          * @name ngInclude#$includeContentError
24414          * @eventType emit on the scope ngInclude was declared in
24415          * @description
24416          * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
24417          *
24418          * @param {Object} angularEvent Synthetic event object.
24419          * @param {String} src URL of content to load.
24420          */
24421         var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
24422                           function($templateRequest,   $anchorScroll,   $animate) {
24423           return {
24424             restrict: 'ECA',
24425             priority: 400,
24426             terminal: true,
24427             transclude: 'element',
24428             controller: angular.noop,
24429             compile: function(element, attr) {
24430               var srcExp = attr.ngInclude || attr.src,
24431                   onloadExp = attr.onload || '',
24432                   autoScrollExp = attr.autoscroll;
24433
24434               return function(scope, $element, $attr, ctrl, $transclude) {
24435                 var changeCounter = 0,
24436                     currentScope,
24437                     previousElement,
24438                     currentElement;
24439
24440                 var cleanupLastIncludeContent = function() {
24441                   if (previousElement) {
24442                     previousElement.remove();
24443                     previousElement = null;
24444                   }
24445                   if (currentScope) {
24446                     currentScope.$destroy();
24447                     currentScope = null;
24448                   }
24449                   if (currentElement) {
24450                     $animate.leave(currentElement).then(function() {
24451                       previousElement = null;
24452                     });
24453                     previousElement = currentElement;
24454                     currentElement = null;
24455                   }
24456                 };
24457
24458                 scope.$watch(srcExp, function ngIncludeWatchAction(src) {
24459                   var afterAnimation = function() {
24460                     if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
24461                       $anchorScroll();
24462                     }
24463                   };
24464                   var thisChangeId = ++changeCounter;
24465
24466                   if (src) {
24467                     //set the 2nd param to true to ignore the template request error so that the inner
24468                     //contents and scope can be cleaned up.
24469                     $templateRequest(src, true).then(function(response) {
24470                       if (thisChangeId !== changeCounter) return;
24471                       var newScope = scope.$new();
24472                       ctrl.template = response;
24473
24474                       // Note: This will also link all children of ng-include that were contained in the original
24475                       // html. If that content contains controllers, ... they could pollute/change the scope.
24476                       // However, using ng-include on an element with additional content does not make sense...
24477                       // Note: We can't remove them in the cloneAttchFn of $transclude as that
24478                       // function is called before linking the content, which would apply child
24479                       // directives to non existing elements.
24480                       var clone = $transclude(newScope, function(clone) {
24481                         cleanupLastIncludeContent();
24482                         $animate.enter(clone, null, $element).then(afterAnimation);
24483                       });
24484
24485                       currentScope = newScope;
24486                       currentElement = clone;
24487
24488                       currentScope.$emit('$includeContentLoaded', src);
24489                       scope.$eval(onloadExp);
24490                     }, function() {
24491                       if (thisChangeId === changeCounter) {
24492                         cleanupLastIncludeContent();
24493                         scope.$emit('$includeContentError', src);
24494                       }
24495                     });
24496                     scope.$emit('$includeContentRequested', src);
24497                   } else {
24498                     cleanupLastIncludeContent();
24499                     ctrl.template = null;
24500                   }
24501                 });
24502               };
24503             }
24504           };
24505         }];
24506
24507         // This directive is called during the $transclude call of the first `ngInclude` directive.
24508         // It will replace and compile the content of the element with the loaded template.
24509         // We need this directive so that the element content is already filled when
24510         // the link function of another directive on the same element as ngInclude
24511         // is called.
24512         var ngIncludeFillContentDirective = ['$compile',
24513           function($compile) {
24514             return {
24515               restrict: 'ECA',
24516               priority: -400,
24517               require: 'ngInclude',
24518               link: function(scope, $element, $attr, ctrl) {
24519                 if (/SVG/.test($element[0].toString())) {
24520                   // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
24521                   // support innerHTML, so detect this here and try to generate the contents
24522                   // specially.
24523                   $element.empty();
24524                   $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
24525                       function namespaceAdaptedClone(clone) {
24526                     $element.append(clone);
24527                   }, {futureParentElement: $element});
24528                   return;
24529                 }
24530
24531                 $element.html(ctrl.template);
24532                 $compile($element.contents())(scope);
24533               }
24534             };
24535           }];
24536
24537         /**
24538          * @ngdoc directive
24539          * @name ngInit
24540          * @restrict AC
24541          *
24542          * @description
24543          * The `ngInit` directive allows you to evaluate an expression in the
24544          * current scope.
24545          *
24546          * <div class="alert alert-danger">
24547          * This directive can be abused to add unnecessary amounts of logic into your templates.
24548          * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
24549          * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
24550          * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
24551          * rather than `ngInit` to initialize values on a scope.
24552          * </div>
24553          *
24554          * <div class="alert alert-warning">
24555          * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
24556          * sure you have parentheses to ensure correct operator precedence:
24557          * <pre class="prettyprint">
24558          * `<div ng-init="test1 = ($index | toString)"></div>`
24559          * </pre>
24560          * </div>
24561          *
24562          * @priority 450
24563          *
24564          * @element ANY
24565          * @param {expression} ngInit {@link guide/expression Expression} to eval.
24566          *
24567          * @example
24568            <example module="initExample">
24569              <file name="index.html">
24570            <script>
24571              angular.module('initExample', [])
24572                .controller('ExampleController', ['$scope', function($scope) {
24573                  $scope.list = [['a', 'b'], ['c', 'd']];
24574                }]);
24575            </script>
24576            <div ng-controller="ExampleController">
24577              <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
24578                <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
24579                   <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
24580                </div>
24581              </div>
24582            </div>
24583              </file>
24584              <file name="protractor.js" type="protractor">
24585                it('should alias index positions', function() {
24586                  var elements = element.all(by.css('.example-init'));
24587                  expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
24588                  expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
24589                  expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
24590                  expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
24591                });
24592              </file>
24593            </example>
24594          */
24595         var ngInitDirective = ngDirective({
24596           priority: 450,
24597           compile: function() {
24598             return {
24599               pre: function(scope, element, attrs) {
24600                 scope.$eval(attrs.ngInit);
24601               }
24602             };
24603           }
24604         });
24605
24606         /**
24607          * @ngdoc directive
24608          * @name ngList
24609          *
24610          * @description
24611          * Text input that converts between a delimited string and an array of strings. The default
24612          * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
24613          * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
24614          *
24615          * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
24616          * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
24617          *   list item is respected. This implies that the user of the directive is responsible for
24618          *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
24619          *   tab or newline character.
24620          * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
24621          *   when joining the list items back together) and whitespace around each list item is stripped
24622          *   before it is added to the model.
24623          *
24624          * ### Example with Validation
24625          *
24626          * <example name="ngList-directive" module="listExample">
24627          *   <file name="app.js">
24628          *      angular.module('listExample', [])
24629          *        .controller('ExampleController', ['$scope', function($scope) {
24630          *          $scope.names = ['morpheus', 'neo', 'trinity'];
24631          *        }]);
24632          *   </file>
24633          *   <file name="index.html">
24634          *    <form name="myForm" ng-controller="ExampleController">
24635          *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
24636          *      <span role="alert">
24637          *        <span class="error" ng-show="myForm.namesInput.$error.required">
24638          *        Required!</span>
24639          *      </span>
24640          *      <br>
24641          *      <tt>names = {{names}}</tt><br/>
24642          *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
24643          *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
24644          *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
24645          *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
24646          *     </form>
24647          *   </file>
24648          *   <file name="protractor.js" type="protractor">
24649          *     var listInput = element(by.model('names'));
24650          *     var names = element(by.exactBinding('names'));
24651          *     var valid = element(by.binding('myForm.namesInput.$valid'));
24652          *     var error = element(by.css('span.error'));
24653          *
24654          *     it('should initialize to model', function() {
24655          *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
24656          *       expect(valid.getText()).toContain('true');
24657          *       expect(error.getCssValue('display')).toBe('none');
24658          *     });
24659          *
24660          *     it('should be invalid if empty', function() {
24661          *       listInput.clear();
24662          *       listInput.sendKeys('');
24663          *
24664          *       expect(names.getText()).toContain('');
24665          *       expect(valid.getText()).toContain('false');
24666          *       expect(error.getCssValue('display')).not.toBe('none');
24667          *     });
24668          *   </file>
24669          * </example>
24670          *
24671          * ### Example - splitting on newline
24672          * <example name="ngList-directive-newlines">
24673          *   <file name="index.html">
24674          *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
24675          *    <pre>{{ list | json }}</pre>
24676          *   </file>
24677          *   <file name="protractor.js" type="protractor">
24678          *     it("should split the text by newlines", function() {
24679          *       var listInput = element(by.model('list'));
24680          *       var output = element(by.binding('list | json'));
24681          *       listInput.sendKeys('abc\ndef\nghi');
24682          *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
24683          *     });
24684          *   </file>
24685          * </example>
24686          *
24687          * @element input
24688          * @param {string=} ngList optional delimiter that should be used to split the value.
24689          */
24690         var ngListDirective = function() {
24691           return {
24692             restrict: 'A',
24693             priority: 100,
24694             require: 'ngModel',
24695             link: function(scope, element, attr, ctrl) {
24696               // We want to control whitespace trimming so we use this convoluted approach
24697               // to access the ngList attribute, which doesn't pre-trim the attribute
24698               var ngList = element.attr(attr.$attr.ngList) || ', ';
24699               var trimValues = attr.ngTrim !== 'false';
24700               var separator = trimValues ? trim(ngList) : ngList;
24701
24702               var parse = function(viewValue) {
24703                 // If the viewValue is invalid (say required but empty) it will be `undefined`
24704                 if (isUndefined(viewValue)) return;
24705
24706                 var list = [];
24707
24708                 if (viewValue) {
24709                   forEach(viewValue.split(separator), function(value) {
24710                     if (value) list.push(trimValues ? trim(value) : value);
24711                   });
24712                 }
24713
24714                 return list;
24715               };
24716
24717               ctrl.$parsers.push(parse);
24718               ctrl.$formatters.push(function(value) {
24719                 if (isArray(value)) {
24720                   return value.join(ngList);
24721                 }
24722
24723                 return undefined;
24724               });
24725
24726               // Override the standard $isEmpty because an empty array means the input is empty.
24727               ctrl.$isEmpty = function(value) {
24728                 return !value || !value.length;
24729               };
24730             }
24731           };
24732         };
24733
24734         /* global VALID_CLASS: true,
24735           INVALID_CLASS: true,
24736           PRISTINE_CLASS: true,
24737           DIRTY_CLASS: true,
24738           UNTOUCHED_CLASS: true,
24739           TOUCHED_CLASS: true,
24740         */
24741
24742         var VALID_CLASS = 'ng-valid',
24743             INVALID_CLASS = 'ng-invalid',
24744             PRISTINE_CLASS = 'ng-pristine',
24745             DIRTY_CLASS = 'ng-dirty',
24746             UNTOUCHED_CLASS = 'ng-untouched',
24747             TOUCHED_CLASS = 'ng-touched',
24748             PENDING_CLASS = 'ng-pending';
24749
24750         var ngModelMinErr = minErr('ngModel');
24751
24752         /**
24753          * @ngdoc type
24754          * @name ngModel.NgModelController
24755          *
24756          * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
24757          * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
24758          * is set.
24759          * @property {*} $modelValue The value in the model that the control is bound to.
24760          * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
24761                the control reads value from the DOM. The functions are called in array order, each passing
24762                its return value through to the next. The last return value is forwarded to the
24763                {@link ngModel.NgModelController#$validators `$validators`} collection.
24764
24765         Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
24766         `$viewValue`}.
24767
24768         Returning `undefined` from a parser means a parse error occurred. In that case,
24769         no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
24770         will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
24771         is set to `true`. The parse error is stored in `ngModel.$error.parse`.
24772
24773          *
24774          * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
24775                the model value changes. The functions are called in reverse array order, each passing the value through to the
24776                next. The last return value is used as the actual DOM value.
24777                Used to format / convert values for display in the control.
24778          * ```js
24779          * function formatter(value) {
24780          *   if (value) {
24781          *     return value.toUpperCase();
24782          *   }
24783          * }
24784          * ngModel.$formatters.push(formatter);
24785          * ```
24786          *
24787          * @property {Object.<string, function>} $validators A collection of validators that are applied
24788          *      whenever the model value changes. The key value within the object refers to the name of the
24789          *      validator while the function refers to the validation operation. The validation operation is
24790          *      provided with the model value as an argument and must return a true or false value depending
24791          *      on the response of that validation.
24792          *
24793          * ```js
24794          * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
24795          *   var value = modelValue || viewValue;
24796          *   return /[0-9]+/.test(value) &&
24797          *          /[a-z]+/.test(value) &&
24798          *          /[A-Z]+/.test(value) &&
24799          *          /\W+/.test(value);
24800          * };
24801          * ```
24802          *
24803          * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
24804          *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
24805          *      is expected to return a promise when it is run during the model validation process. Once the promise
24806          *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
24807          *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
24808          *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
24809          *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
24810          *      will only run once all synchronous validators have passed.
24811          *
24812          * Please note that if $http is used then it is important that the server returns a success HTTP response code
24813          * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
24814          *
24815          * ```js
24816          * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
24817          *   var value = modelValue || viewValue;
24818          *
24819          *   // Lookup user by username
24820          *   return $http.get('/api/users/' + value).
24821          *      then(function resolved() {
24822          *        //username exists, this means validation fails
24823          *        return $q.reject('exists');
24824          *      }, function rejected() {
24825          *        //username does not exist, therefore this validation passes
24826          *        return true;
24827          *      });
24828          * };
24829          * ```
24830          *
24831          * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
24832          *     view value has changed. It is called with no arguments, and its return value is ignored.
24833          *     This can be used in place of additional $watches against the model value.
24834          *
24835          * @property {Object} $error An object hash with all failing validator ids as keys.
24836          * @property {Object} $pending An object hash with all pending validator ids as keys.
24837          *
24838          * @property {boolean} $untouched True if control has not lost focus yet.
24839          * @property {boolean} $touched True if control has lost focus.
24840          * @property {boolean} $pristine True if user has not interacted with the control yet.
24841          * @property {boolean} $dirty True if user has already interacted with the control.
24842          * @property {boolean} $valid True if there is no error.
24843          * @property {boolean} $invalid True if at least one error on the control.
24844          * @property {string} $name The name attribute of the control.
24845          *
24846          * @description
24847          *
24848          * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
24849          * The controller contains services for data-binding, validation, CSS updates, and value formatting
24850          * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
24851          * listening to DOM events.
24852          * Such DOM related logic should be provided by other directives which make use of
24853          * `NgModelController` for data-binding to control elements.
24854          * Angular provides this DOM logic for most {@link input `input`} elements.
24855          * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
24856          * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
24857          *
24858          * @example
24859          * ### Custom Control Example
24860          * This example shows how to use `NgModelController` with a custom control to achieve
24861          * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
24862          * collaborate together to achieve the desired result.
24863          *
24864          * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
24865          * contents be edited in place by the user.
24866          *
24867          * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
24868          * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
24869          * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
24870          * that content using the `$sce` service.
24871          *
24872          * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
24873             <file name="style.css">
24874               [contenteditable] {
24875                 border: 1px solid black;
24876                 background-color: white;
24877                 min-height: 20px;
24878               }
24879
24880               .ng-invalid {
24881                 border: 1px solid red;
24882               }
24883
24884             </file>
24885             <file name="script.js">
24886               angular.module('customControl', ['ngSanitize']).
24887                 directive('contenteditable', ['$sce', function($sce) {
24888                   return {
24889                     restrict: 'A', // only activate on element attribute
24890                     require: '?ngModel', // get a hold of NgModelController
24891                     link: function(scope, element, attrs, ngModel) {
24892                       if (!ngModel) return; // do nothing if no ng-model
24893
24894                       // Specify how UI should be updated
24895                       ngModel.$render = function() {
24896                         element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
24897                       };
24898
24899                       // Listen for change events to enable binding
24900                       element.on('blur keyup change', function() {
24901                         scope.$evalAsync(read);
24902                       });
24903                       read(); // initialize
24904
24905                       // Write data to the model
24906                       function read() {
24907                         var html = element.html();
24908                         // When we clear the content editable the browser leaves a <br> behind
24909                         // If strip-br attribute is provided then we strip this out
24910                         if ( attrs.stripBr && html == '<br>' ) {
24911                           html = '';
24912                         }
24913                         ngModel.$setViewValue(html);
24914                       }
24915                     }
24916                   };
24917                 }]);
24918             </file>
24919             <file name="index.html">
24920               <form name="myForm">
24921                <div contenteditable
24922                     name="myWidget" ng-model="userContent"
24923                     strip-br="true"
24924                     required>Change me!</div>
24925                 <span ng-show="myForm.myWidget.$error.required">Required!</span>
24926                <hr>
24927                <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
24928               </form>
24929             </file>
24930             <file name="protractor.js" type="protractor">
24931             it('should data-bind and become invalid', function() {
24932               if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
24933                 // SafariDriver can't handle contenteditable
24934                 // and Firefox driver can't clear contenteditables very well
24935                 return;
24936               }
24937               var contentEditable = element(by.css('[contenteditable]'));
24938               var content = 'Change me!';
24939
24940               expect(contentEditable.getText()).toEqual(content);
24941
24942               contentEditable.clear();
24943               contentEditable.sendKeys(protractor.Key.BACK_SPACE);
24944               expect(contentEditable.getText()).toEqual('');
24945               expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
24946             });
24947             </file>
24948          * </example>
24949          *
24950          *
24951          */
24952         var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
24953             function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
24954           this.$viewValue = Number.NaN;
24955           this.$modelValue = Number.NaN;
24956           this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
24957           this.$validators = {};
24958           this.$asyncValidators = {};
24959           this.$parsers = [];
24960           this.$formatters = [];
24961           this.$viewChangeListeners = [];
24962           this.$untouched = true;
24963           this.$touched = false;
24964           this.$pristine = true;
24965           this.$dirty = false;
24966           this.$valid = true;
24967           this.$invalid = false;
24968           this.$error = {}; // keep invalid keys here
24969           this.$$success = {}; // keep valid keys here
24970           this.$pending = undefined; // keep pending keys here
24971           this.$name = $interpolate($attr.name || '', false)($scope);
24972           this.$$parentForm = nullFormCtrl;
24973
24974           var parsedNgModel = $parse($attr.ngModel),
24975               parsedNgModelAssign = parsedNgModel.assign,
24976               ngModelGet = parsedNgModel,
24977               ngModelSet = parsedNgModelAssign,
24978               pendingDebounce = null,
24979               parserValid,
24980               ctrl = this;
24981
24982           this.$$setOptions = function(options) {
24983             ctrl.$options = options;
24984             if (options && options.getterSetter) {
24985               var invokeModelGetter = $parse($attr.ngModel + '()'),
24986                   invokeModelSetter = $parse($attr.ngModel + '($$$p)');
24987
24988               ngModelGet = function($scope) {
24989                 var modelValue = parsedNgModel($scope);
24990                 if (isFunction(modelValue)) {
24991                   modelValue = invokeModelGetter($scope);
24992                 }
24993                 return modelValue;
24994               };
24995               ngModelSet = function($scope, newValue) {
24996                 if (isFunction(parsedNgModel($scope))) {
24997                   invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
24998                 } else {
24999                   parsedNgModelAssign($scope, ctrl.$modelValue);
25000                 }
25001               };
25002             } else if (!parsedNgModel.assign) {
25003               throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
25004                   $attr.ngModel, startingTag($element));
25005             }
25006           };
25007
25008           /**
25009            * @ngdoc method
25010            * @name ngModel.NgModelController#$render
25011            *
25012            * @description
25013            * Called when the view needs to be updated. It is expected that the user of the ng-model
25014            * directive will implement this method.
25015            *
25016            * The `$render()` method is invoked in the following situations:
25017            *
25018            * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
25019            *   committed value then `$render()` is called to update the input control.
25020            * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
25021            *   the `$viewValue` are different from last time.
25022            *
25023            * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
25024            * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
25025            * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
25026            * invoked if you only change a property on the objects.
25027            */
25028           this.$render = noop;
25029
25030           /**
25031            * @ngdoc method
25032            * @name ngModel.NgModelController#$isEmpty
25033            *
25034            * @description
25035            * This is called when we need to determine if the value of an input is empty.
25036            *
25037            * For instance, the required directive does this to work out if the input has data or not.
25038            *
25039            * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
25040            *
25041            * You can override this for input directives whose concept of being empty is different from the
25042            * default. The `checkboxInputType` directive does this because in its case a value of `false`
25043            * implies empty.
25044            *
25045            * @param {*} value The value of the input to check for emptiness.
25046            * @returns {boolean} True if `value` is "empty".
25047            */
25048           this.$isEmpty = function(value) {
25049             return isUndefined(value) || value === '' || value === null || value !== value;
25050           };
25051
25052           var currentValidationRunId = 0;
25053
25054           /**
25055            * @ngdoc method
25056            * @name ngModel.NgModelController#$setValidity
25057            *
25058            * @description
25059            * Change the validity state, and notify the form.
25060            *
25061            * This method can be called within $parsers/$formatters or a custom validation implementation.
25062            * However, in most cases it should be sufficient to use the `ngModel.$validators` and
25063            * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
25064            *
25065            * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
25066            *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
25067            *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
25068            *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
25069            *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
25070            *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
25071            * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
25072            *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
25073            *                          Skipped is used by Angular when validators do not run because of parse errors and
25074            *                          when `$asyncValidators` do not run because any of the `$validators` failed.
25075            */
25076           addSetValidityMethod({
25077             ctrl: this,
25078             $element: $element,
25079             set: function(object, property) {
25080               object[property] = true;
25081             },
25082             unset: function(object, property) {
25083               delete object[property];
25084             },
25085             $animate: $animate
25086           });
25087
25088           /**
25089            * @ngdoc method
25090            * @name ngModel.NgModelController#$setPristine
25091            *
25092            * @description
25093            * Sets the control to its pristine state.
25094            *
25095            * This method can be called to remove the `ng-dirty` class and set the control to its pristine
25096            * state (`ng-pristine` class). A model is considered to be pristine when the control
25097            * has not been changed from when first compiled.
25098            */
25099           this.$setPristine = function() {
25100             ctrl.$dirty = false;
25101             ctrl.$pristine = true;
25102             $animate.removeClass($element, DIRTY_CLASS);
25103             $animate.addClass($element, PRISTINE_CLASS);
25104           };
25105
25106           /**
25107            * @ngdoc method
25108            * @name ngModel.NgModelController#$setDirty
25109            *
25110            * @description
25111            * Sets the control to its dirty state.
25112            *
25113            * This method can be called to remove the `ng-pristine` class and set the control to its dirty
25114            * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
25115            * from when first compiled.
25116            */
25117           this.$setDirty = function() {
25118             ctrl.$dirty = true;
25119             ctrl.$pristine = false;
25120             $animate.removeClass($element, PRISTINE_CLASS);
25121             $animate.addClass($element, DIRTY_CLASS);
25122             ctrl.$$parentForm.$setDirty();
25123           };
25124
25125           /**
25126            * @ngdoc method
25127            * @name ngModel.NgModelController#$setUntouched
25128            *
25129            * @description
25130            * Sets the control to its untouched state.
25131            *
25132            * This method can be called to remove the `ng-touched` class and set the control to its
25133            * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
25134            * by default, however this function can be used to restore that state if the model has
25135            * already been touched by the user.
25136            */
25137           this.$setUntouched = function() {
25138             ctrl.$touched = false;
25139             ctrl.$untouched = true;
25140             $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
25141           };
25142
25143           /**
25144            * @ngdoc method
25145            * @name ngModel.NgModelController#$setTouched
25146            *
25147            * @description
25148            * Sets the control to its touched state.
25149            *
25150            * This method can be called to remove the `ng-untouched` class and set the control to its
25151            * touched state (`ng-touched` class). A model is considered to be touched when the user has
25152            * first focused the control element and then shifted focus away from the control (blur event).
25153            */
25154           this.$setTouched = function() {
25155             ctrl.$touched = true;
25156             ctrl.$untouched = false;
25157             $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
25158           };
25159
25160           /**
25161            * @ngdoc method
25162            * @name ngModel.NgModelController#$rollbackViewValue
25163            *
25164            * @description
25165            * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
25166            * which may be caused by a pending debounced event or because the input is waiting for a some
25167            * future event.
25168            *
25169            * If you have an input that uses `ng-model-options` to set up debounced events or events such
25170            * as blur you can have a situation where there is a period when the `$viewValue`
25171            * is out of synch with the ngModel's `$modelValue`.
25172            *
25173            * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
25174            * programmatically before these debounced/future events have resolved/occurred, because Angular's
25175            * dirty checking mechanism is not able to tell whether the model has actually changed or not.
25176            *
25177            * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
25178            * input which may have such events pending. This is important in order to make sure that the
25179            * input field will be updated with the new model value and any pending operations are cancelled.
25180            *
25181            * <example name="ng-model-cancel-update" module="cancel-update-example">
25182            *   <file name="app.js">
25183            *     angular.module('cancel-update-example', [])
25184            *
25185            *     .controller('CancelUpdateController', ['$scope', function($scope) {
25186            *       $scope.resetWithCancel = function(e) {
25187            *         if (e.keyCode == 27) {
25188            *           $scope.myForm.myInput1.$rollbackViewValue();
25189            *           $scope.myValue = '';
25190            *         }
25191            *       };
25192            *       $scope.resetWithoutCancel = function(e) {
25193            *         if (e.keyCode == 27) {
25194            *           $scope.myValue = '';
25195            *         }
25196            *       };
25197            *     }]);
25198            *   </file>
25199            *   <file name="index.html">
25200            *     <div ng-controller="CancelUpdateController">
25201            *       <p>Try typing something in each input.  See that the model only updates when you
25202            *          blur off the input.
25203            *        </p>
25204            *        <p>Now see what happens if you start typing then press the Escape key</p>
25205            *
25206            *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
25207            *         <p id="inputDescription1">With $rollbackViewValue()</p>
25208            *         <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
25209            *                ng-keydown="resetWithCancel($event)"><br/>
25210            *         myValue: "{{ myValue }}"
25211            *
25212            *         <p id="inputDescription2">Without $rollbackViewValue()</p>
25213            *         <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
25214            *                ng-keydown="resetWithoutCancel($event)"><br/>
25215            *         myValue: "{{ myValue }}"
25216            *       </form>
25217            *     </div>
25218            *   </file>
25219            * </example>
25220            */
25221           this.$rollbackViewValue = function() {
25222             $timeout.cancel(pendingDebounce);
25223             ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
25224             ctrl.$render();
25225           };
25226
25227           /**
25228            * @ngdoc method
25229            * @name ngModel.NgModelController#$validate
25230            *
25231            * @description
25232            * Runs each of the registered validators (first synchronous validators and then
25233            * asynchronous validators).
25234            * If the validity changes to invalid, the model will be set to `undefined`,
25235            * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
25236            * If the validity changes to valid, it will set the model to the last available valid
25237            * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
25238            */
25239           this.$validate = function() {
25240             // ignore $validate before model is initialized
25241             if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
25242               return;
25243             }
25244
25245             var viewValue = ctrl.$$lastCommittedViewValue;
25246             // Note: we use the $$rawModelValue as $modelValue might have been
25247             // set to undefined during a view -> model update that found validation
25248             // errors. We can't parse the view here, since that could change
25249             // the model although neither viewValue nor the model on the scope changed
25250             var modelValue = ctrl.$$rawModelValue;
25251
25252             var prevValid = ctrl.$valid;
25253             var prevModelValue = ctrl.$modelValue;
25254
25255             var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
25256
25257             ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
25258               // If there was no change in validity, don't update the model
25259               // This prevents changing an invalid modelValue to undefined
25260               if (!allowInvalid && prevValid !== allValid) {
25261                 // Note: Don't check ctrl.$valid here, as we could have
25262                 // external validators (e.g. calculated on the server),
25263                 // that just call $setValidity and need the model value
25264                 // to calculate their validity.
25265                 ctrl.$modelValue = allValid ? modelValue : undefined;
25266
25267                 if (ctrl.$modelValue !== prevModelValue) {
25268                   ctrl.$$writeModelToScope();
25269                 }
25270               }
25271             });
25272
25273           };
25274
25275           this.$$runValidators = function(modelValue, viewValue, doneCallback) {
25276             currentValidationRunId++;
25277             var localValidationRunId = currentValidationRunId;
25278
25279             // check parser error
25280             if (!processParseErrors()) {
25281               validationDone(false);
25282               return;
25283             }
25284             if (!processSyncValidators()) {
25285               validationDone(false);
25286               return;
25287             }
25288             processAsyncValidators();
25289
25290             function processParseErrors() {
25291               var errorKey = ctrl.$$parserName || 'parse';
25292               if (isUndefined(parserValid)) {
25293                 setValidity(errorKey, null);
25294               } else {
25295                 if (!parserValid) {
25296                   forEach(ctrl.$validators, function(v, name) {
25297                     setValidity(name, null);
25298                   });
25299                   forEach(ctrl.$asyncValidators, function(v, name) {
25300                     setValidity(name, null);
25301                   });
25302                 }
25303                 // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
25304                 setValidity(errorKey, parserValid);
25305                 return parserValid;
25306               }
25307               return true;
25308             }
25309
25310             function processSyncValidators() {
25311               var syncValidatorsValid = true;
25312               forEach(ctrl.$validators, function(validator, name) {
25313                 var result = validator(modelValue, viewValue);
25314                 syncValidatorsValid = syncValidatorsValid && result;
25315                 setValidity(name, result);
25316               });
25317               if (!syncValidatorsValid) {
25318                 forEach(ctrl.$asyncValidators, function(v, name) {
25319                   setValidity(name, null);
25320                 });
25321                 return false;
25322               }
25323               return true;
25324             }
25325
25326             function processAsyncValidators() {
25327               var validatorPromises = [];
25328               var allValid = true;
25329               forEach(ctrl.$asyncValidators, function(validator, name) {
25330                 var promise = validator(modelValue, viewValue);
25331                 if (!isPromiseLike(promise)) {
25332                   throw ngModelMinErr("$asyncValidators",
25333                     "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
25334                 }
25335                 setValidity(name, undefined);
25336                 validatorPromises.push(promise.then(function() {
25337                   setValidity(name, true);
25338                 }, function(error) {
25339                   allValid = false;
25340                   setValidity(name, false);
25341                 }));
25342               });
25343               if (!validatorPromises.length) {
25344                 validationDone(true);
25345               } else {
25346                 $q.all(validatorPromises).then(function() {
25347                   validationDone(allValid);
25348                 }, noop);
25349               }
25350             }
25351
25352             function setValidity(name, isValid) {
25353               if (localValidationRunId === currentValidationRunId) {
25354                 ctrl.$setValidity(name, isValid);
25355               }
25356             }
25357
25358             function validationDone(allValid) {
25359               if (localValidationRunId === currentValidationRunId) {
25360
25361                 doneCallback(allValid);
25362               }
25363             }
25364           };
25365
25366           /**
25367            * @ngdoc method
25368            * @name ngModel.NgModelController#$commitViewValue
25369            *
25370            * @description
25371            * Commit a pending update to the `$modelValue`.
25372            *
25373            * Updates may be pending by a debounced event or because the input is waiting for a some future
25374            * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
25375            * usually handles calling this in response to input events.
25376            */
25377           this.$commitViewValue = function() {
25378             var viewValue = ctrl.$viewValue;
25379
25380             $timeout.cancel(pendingDebounce);
25381
25382             // If the view value has not changed then we should just exit, except in the case where there is
25383             // a native validator on the element. In this case the validation state may have changed even though
25384             // the viewValue has stayed empty.
25385             if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
25386               return;
25387             }
25388             ctrl.$$lastCommittedViewValue = viewValue;
25389
25390             // change to dirty
25391             if (ctrl.$pristine) {
25392               this.$setDirty();
25393             }
25394             this.$$parseAndValidate();
25395           };
25396
25397           this.$$parseAndValidate = function() {
25398             var viewValue = ctrl.$$lastCommittedViewValue;
25399             var modelValue = viewValue;
25400             parserValid = isUndefined(modelValue) ? undefined : true;
25401
25402             if (parserValid) {
25403               for (var i = 0; i < ctrl.$parsers.length; i++) {
25404                 modelValue = ctrl.$parsers[i](modelValue);
25405                 if (isUndefined(modelValue)) {
25406                   parserValid = false;
25407                   break;
25408                 }
25409               }
25410             }
25411             if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
25412               // ctrl.$modelValue has not been touched yet...
25413               ctrl.$modelValue = ngModelGet($scope);
25414             }
25415             var prevModelValue = ctrl.$modelValue;
25416             var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
25417             ctrl.$$rawModelValue = modelValue;
25418
25419             if (allowInvalid) {
25420               ctrl.$modelValue = modelValue;
25421               writeToModelIfNeeded();
25422             }
25423
25424             // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
25425             // This can happen if e.g. $setViewValue is called from inside a parser
25426             ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
25427               if (!allowInvalid) {
25428                 // Note: Don't check ctrl.$valid here, as we could have
25429                 // external validators (e.g. calculated on the server),
25430                 // that just call $setValidity and need the model value
25431                 // to calculate their validity.
25432                 ctrl.$modelValue = allValid ? modelValue : undefined;
25433                 writeToModelIfNeeded();
25434               }
25435             });
25436
25437             function writeToModelIfNeeded() {
25438               if (ctrl.$modelValue !== prevModelValue) {
25439                 ctrl.$$writeModelToScope();
25440               }
25441             }
25442           };
25443
25444           this.$$writeModelToScope = function() {
25445             ngModelSet($scope, ctrl.$modelValue);
25446             forEach(ctrl.$viewChangeListeners, function(listener) {
25447               try {
25448                 listener();
25449               } catch (e) {
25450                 $exceptionHandler(e);
25451               }
25452             });
25453           };
25454
25455           /**
25456            * @ngdoc method
25457            * @name ngModel.NgModelController#$setViewValue
25458            *
25459            * @description
25460            * Update the view value.
25461            *
25462            * This method should be called when a control wants to change the view value; typically,
25463            * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
25464            * directive calls it when the value of the input changes and {@link ng.directive:select select}
25465            * calls it when an option is selected.
25466            *
25467            * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
25468            * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
25469            * value sent directly for processing, finally to be applied to `$modelValue` and then the
25470            * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
25471            * in the `$viewChangeListeners` list, are called.
25472            *
25473            * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
25474            * and the `default` trigger is not listed, all those actions will remain pending until one of the
25475            * `updateOn` events is triggered on the DOM element.
25476            * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
25477            * directive is used with a custom debounce for this particular event.
25478            * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
25479            * is specified, once the timer runs out.
25480            *
25481            * When used with standard inputs, the view value will always be a string (which is in some cases
25482            * parsed into another type, such as a `Date` object for `input[date]`.)
25483            * However, custom controls might also pass objects to this method. In this case, we should make
25484            * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
25485            * perform a deep watch of objects, it only looks for a change of identity. If you only change
25486            * the property of the object then ngModel will not realise that the object has changed and
25487            * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
25488            * not change properties of the copy once it has been passed to `$setViewValue`.
25489            * Otherwise you may cause the model value on the scope to change incorrectly.
25490            *
25491            * <div class="alert alert-info">
25492            * In any case, the value passed to the method should always reflect the current value
25493            * of the control. For example, if you are calling `$setViewValue` for an input element,
25494            * you should pass the input DOM value. Otherwise, the control and the scope model become
25495            * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
25496            * the control's DOM value in any way. If we want to change the control's DOM value
25497            * programmatically, we should update the `ngModel` scope expression. Its new value will be
25498            * picked up by the model controller, which will run it through the `$formatters`, `$render` it
25499            * to update the DOM, and finally call `$validate` on it.
25500            * </div>
25501            *
25502            * @param {*} value value from the view.
25503            * @param {string} trigger Event that triggered the update.
25504            */
25505           this.$setViewValue = function(value, trigger) {
25506             ctrl.$viewValue = value;
25507             if (!ctrl.$options || ctrl.$options.updateOnDefault) {
25508               ctrl.$$debounceViewValueCommit(trigger);
25509             }
25510           };
25511
25512           this.$$debounceViewValueCommit = function(trigger) {
25513             var debounceDelay = 0,
25514                 options = ctrl.$options,
25515                 debounce;
25516
25517             if (options && isDefined(options.debounce)) {
25518               debounce = options.debounce;
25519               if (isNumber(debounce)) {
25520                 debounceDelay = debounce;
25521               } else if (isNumber(debounce[trigger])) {
25522                 debounceDelay = debounce[trigger];
25523               } else if (isNumber(debounce['default'])) {
25524                 debounceDelay = debounce['default'];
25525               }
25526             }
25527
25528             $timeout.cancel(pendingDebounce);
25529             if (debounceDelay) {
25530               pendingDebounce = $timeout(function() {
25531                 ctrl.$commitViewValue();
25532               }, debounceDelay);
25533             } else if ($rootScope.$$phase) {
25534               ctrl.$commitViewValue();
25535             } else {
25536               $scope.$apply(function() {
25537                 ctrl.$commitViewValue();
25538               });
25539             }
25540           };
25541
25542           // model -> value
25543           // Note: we cannot use a normal scope.$watch as we want to detect the following:
25544           // 1. scope value is 'a'
25545           // 2. user enters 'b'
25546           // 3. ng-change kicks in and reverts scope value to 'a'
25547           //    -> scope value did not change since the last digest as
25548           //       ng-change executes in apply phase
25549           // 4. view should be changed back to 'a'
25550           $scope.$watch(function ngModelWatch() {
25551             var modelValue = ngModelGet($scope);
25552
25553             // if scope model value and ngModel value are out of sync
25554             // TODO(perf): why not move this to the action fn?
25555             if (modelValue !== ctrl.$modelValue &&
25556                // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
25557                (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
25558             ) {
25559               ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
25560               parserValid = undefined;
25561
25562               var formatters = ctrl.$formatters,
25563                   idx = formatters.length;
25564
25565               var viewValue = modelValue;
25566               while (idx--) {
25567                 viewValue = formatters[idx](viewValue);
25568               }
25569               if (ctrl.$viewValue !== viewValue) {
25570                 ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
25571                 ctrl.$render();
25572
25573                 ctrl.$$runValidators(modelValue, viewValue, noop);
25574               }
25575             }
25576
25577             return modelValue;
25578           });
25579         }];
25580
25581
25582         /**
25583          * @ngdoc directive
25584          * @name ngModel
25585          *
25586          * @element input
25587          * @priority 1
25588          *
25589          * @description
25590          * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
25591          * property on the scope using {@link ngModel.NgModelController NgModelController},
25592          * which is created and exposed by this directive.
25593          *
25594          * `ngModel` is responsible for:
25595          *
25596          * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
25597          *   require.
25598          * - Providing validation behavior (i.e. required, number, email, url).
25599          * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
25600          * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
25601          * - Registering the control with its parent {@link ng.directive:form form}.
25602          *
25603          * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
25604          * current scope. If the property doesn't already exist on this scope, it will be created
25605          * implicitly and added to the scope.
25606          *
25607          * For best practices on using `ngModel`, see:
25608          *
25609          *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
25610          *
25611          * For basic examples, how to use `ngModel`, see:
25612          *
25613          *  - {@link ng.directive:input input}
25614          *    - {@link input[text] text}
25615          *    - {@link input[checkbox] checkbox}
25616          *    - {@link input[radio] radio}
25617          *    - {@link input[number] number}
25618          *    - {@link input[email] email}
25619          *    - {@link input[url] url}
25620          *    - {@link input[date] date}
25621          *    - {@link input[datetime-local] datetime-local}
25622          *    - {@link input[time] time}
25623          *    - {@link input[month] month}
25624          *    - {@link input[week] week}
25625          *  - {@link ng.directive:select select}
25626          *  - {@link ng.directive:textarea textarea}
25627          *
25628          * # CSS classes
25629          * The following CSS classes are added and removed on the associated input/select/textarea element
25630          * depending on the validity of the model.
25631          *
25632          *  - `ng-valid`: the model is valid
25633          *  - `ng-invalid`: the model is invalid
25634          *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
25635          *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
25636          *  - `ng-pristine`: the control hasn't been interacted with yet
25637          *  - `ng-dirty`: the control has been interacted with
25638          *  - `ng-touched`: the control has been blurred
25639          *  - `ng-untouched`: the control hasn't been blurred
25640          *  - `ng-pending`: any `$asyncValidators` are unfulfilled
25641          *
25642          * Keep in mind that ngAnimate can detect each of these classes when added and removed.
25643          *
25644          * ## Animation Hooks
25645          *
25646          * Animations within models are triggered when any of the associated CSS classes are added and removed
25647          * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
25648          * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
25649          * The animations that are triggered within ngModel are similar to how they work in ngClass and
25650          * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
25651          *
25652          * The following example shows a simple way to utilize CSS transitions to style an input element
25653          * that has been rendered as invalid after it has been validated:
25654          *
25655          * <pre>
25656          * //be sure to include ngAnimate as a module to hook into more
25657          * //advanced animations
25658          * .my-input {
25659          *   transition:0.5s linear all;
25660          *   background: white;
25661          * }
25662          * .my-input.ng-invalid {
25663          *   background: red;
25664          *   color:white;
25665          * }
25666          * </pre>
25667          *
25668          * @example
25669          * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
25670              <file name="index.html">
25671                <script>
25672                 angular.module('inputExample', [])
25673                   .controller('ExampleController', ['$scope', function($scope) {
25674                     $scope.val = '1';
25675                   }]);
25676                </script>
25677                <style>
25678                  .my-input {
25679                    transition:all linear 0.5s;
25680                    background: transparent;
25681                  }
25682                  .my-input.ng-invalid {
25683                    color:white;
25684                    background: red;
25685                  }
25686                </style>
25687                <p id="inputDescription">
25688                 Update input to see transitions when valid/invalid.
25689                 Integer is a valid value.
25690                </p>
25691                <form name="testForm" ng-controller="ExampleController">
25692                  <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
25693                         aria-describedby="inputDescription" />
25694                </form>
25695              </file>
25696          * </example>
25697          *
25698          * ## Binding to a getter/setter
25699          *
25700          * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
25701          * function that returns a representation of the model when called with zero arguments, and sets
25702          * the internal state of a model when called with an argument. It's sometimes useful to use this
25703          * for models that have an internal representation that's different from what the model exposes
25704          * to the view.
25705          *
25706          * <div class="alert alert-success">
25707          * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
25708          * frequently than other parts of your code.
25709          * </div>
25710          *
25711          * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
25712          * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
25713          * a `<form>`, which will enable this behavior for all `<input>`s within it. See
25714          * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
25715          *
25716          * The following example shows how to use `ngModel` with a getter/setter:
25717          *
25718          * @example
25719          * <example name="ngModel-getter-setter" module="getterSetterExample">
25720              <file name="index.html">
25721                <div ng-controller="ExampleController">
25722                  <form name="userForm">
25723                    <label>Name:
25724                      <input type="text" name="userName"
25725                             ng-model="user.name"
25726                             ng-model-options="{ getterSetter: true }" />
25727                    </label>
25728                  </form>
25729                  <pre>user.name = <span ng-bind="user.name()"></span></pre>
25730                </div>
25731              </file>
25732              <file name="app.js">
25733                angular.module('getterSetterExample', [])
25734                  .controller('ExampleController', ['$scope', function($scope) {
25735                    var _name = 'Brian';
25736                    $scope.user = {
25737                      name: function(newName) {
25738                       // Note that newName can be undefined for two reasons:
25739                       // 1. Because it is called as a getter and thus called with no arguments
25740                       // 2. Because the property should actually be set to undefined. This happens e.g. if the
25741                       //    input is invalid
25742                       return arguments.length ? (_name = newName) : _name;
25743                      }
25744                    };
25745                  }]);
25746              </file>
25747          * </example>
25748          */
25749         var ngModelDirective = ['$rootScope', function($rootScope) {
25750           return {
25751             restrict: 'A',
25752             require: ['ngModel', '^?form', '^?ngModelOptions'],
25753             controller: NgModelController,
25754             // Prelink needs to run before any input directive
25755             // so that we can set the NgModelOptions in NgModelController
25756             // before anyone else uses it.
25757             priority: 1,
25758             compile: function ngModelCompile(element) {
25759               // Setup initial state of the control
25760               element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
25761
25762               return {
25763                 pre: function ngModelPreLink(scope, element, attr, ctrls) {
25764                   var modelCtrl = ctrls[0],
25765                       formCtrl = ctrls[1] || modelCtrl.$$parentForm;
25766
25767                   modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
25768
25769                   // notify others, especially parent forms
25770                   formCtrl.$addControl(modelCtrl);
25771
25772                   attr.$observe('name', function(newValue) {
25773                     if (modelCtrl.$name !== newValue) {
25774                       modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
25775                     }
25776                   });
25777
25778                   scope.$on('$destroy', function() {
25779                     modelCtrl.$$parentForm.$removeControl(modelCtrl);
25780                   });
25781                 },
25782                 post: function ngModelPostLink(scope, element, attr, ctrls) {
25783                   var modelCtrl = ctrls[0];
25784                   if (modelCtrl.$options && modelCtrl.$options.updateOn) {
25785                     element.on(modelCtrl.$options.updateOn, function(ev) {
25786                       modelCtrl.$$debounceViewValueCommit(ev && ev.type);
25787                     });
25788                   }
25789
25790                   element.on('blur', function(ev) {
25791                     if (modelCtrl.$touched) return;
25792
25793                     if ($rootScope.$$phase) {
25794                       scope.$evalAsync(modelCtrl.$setTouched);
25795                     } else {
25796                       scope.$apply(modelCtrl.$setTouched);
25797                     }
25798                   });
25799                 }
25800               };
25801             }
25802           };
25803         }];
25804
25805         var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
25806
25807         /**
25808          * @ngdoc directive
25809          * @name ngModelOptions
25810          *
25811          * @description
25812          * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
25813          * events that will trigger a model update and/or a debouncing delay so that the actual update only
25814          * takes place when a timer expires; this timer will be reset after another change takes place.
25815          *
25816          * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
25817          * be different from the value in the actual model. This means that if you update the model you
25818          * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
25819          * order to make sure it is synchronized with the model and that any debounced action is canceled.
25820          *
25821          * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
25822          * method is by making sure the input is placed inside a form that has a `name` attribute. This is
25823          * important because `form` controllers are published to the related scope under the name in their
25824          * `name` attribute.
25825          *
25826          * Any pending changes will take place immediately when an enclosing form is submitted via the
25827          * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
25828          * to have access to the updated model.
25829          *
25830          * `ngModelOptions` has an effect on the element it's declared on and its descendants.
25831          *
25832          * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
25833          *   - `updateOn`: string specifying which event should the input be bound to. You can set several
25834          *     events using an space delimited list. There is a special event called `default` that
25835          *     matches the default events belonging of the control.
25836          *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
25837          *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
25838          *     custom value for each event. For example:
25839          *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
25840          *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
25841          *     not validate correctly instead of the default behavior of setting the model to undefined.
25842          *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
25843                `ngModel` as getters/setters.
25844          *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
25845          *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
25846          *     continental US time zone abbreviations, but for general use, use a time zone offset, for
25847          *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
25848          *     If not specified, the timezone of the browser will be used.
25849          *
25850          * @example
25851
25852           The following example shows how to override immediate updates. Changes on the inputs within the
25853           form will update the model only when the control loses focus (blur event). If `escape` key is
25854           pressed while the input field is focused, the value is reset to the value in the current model.
25855
25856           <example name="ngModelOptions-directive-blur" module="optionsExample">
25857             <file name="index.html">
25858               <div ng-controller="ExampleController">
25859                 <form name="userForm">
25860                   <label>Name:
25861                     <input type="text" name="userName"
25862                            ng-model="user.name"
25863                            ng-model-options="{ updateOn: 'blur' }"
25864                            ng-keyup="cancel($event)" />
25865                   </label><br />
25866                   <label>Other data:
25867                     <input type="text" ng-model="user.data" />
25868                   </label><br />
25869                 </form>
25870                 <pre>user.name = <span ng-bind="user.name"></span></pre>
25871                 <pre>user.data = <span ng-bind="user.data"></span></pre>
25872               </div>
25873             </file>
25874             <file name="app.js">
25875               angular.module('optionsExample', [])
25876                 .controller('ExampleController', ['$scope', function($scope) {
25877                   $scope.user = { name: 'John', data: '' };
25878
25879                   $scope.cancel = function(e) {
25880                     if (e.keyCode == 27) {
25881                       $scope.userForm.userName.$rollbackViewValue();
25882                     }
25883                   };
25884                 }]);
25885             </file>
25886             <file name="protractor.js" type="protractor">
25887               var model = element(by.binding('user.name'));
25888               var input = element(by.model('user.name'));
25889               var other = element(by.model('user.data'));
25890
25891               it('should allow custom events', function() {
25892                 input.sendKeys(' Doe');
25893                 input.click();
25894                 expect(model.getText()).toEqual('John');
25895                 other.click();
25896                 expect(model.getText()).toEqual('John Doe');
25897               });
25898
25899               it('should $rollbackViewValue when model changes', function() {
25900                 input.sendKeys(' Doe');
25901                 expect(input.getAttribute('value')).toEqual('John Doe');
25902                 input.sendKeys(protractor.Key.ESCAPE);
25903                 expect(input.getAttribute('value')).toEqual('John');
25904                 other.click();
25905                 expect(model.getText()).toEqual('John');
25906               });
25907             </file>
25908           </example>
25909
25910           This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
25911           If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
25912
25913           <example name="ngModelOptions-directive-debounce" module="optionsExample">
25914             <file name="index.html">
25915               <div ng-controller="ExampleController">
25916                 <form name="userForm">
25917                   <label>Name:
25918                     <input type="text" name="userName"
25919                            ng-model="user.name"
25920                            ng-model-options="{ debounce: 1000 }" />
25921                   </label>
25922                   <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
25923                   <br />
25924                 </form>
25925                 <pre>user.name = <span ng-bind="user.name"></span></pre>
25926               </div>
25927             </file>
25928             <file name="app.js">
25929               angular.module('optionsExample', [])
25930                 .controller('ExampleController', ['$scope', function($scope) {
25931                   $scope.user = { name: 'Igor' };
25932                 }]);
25933             </file>
25934           </example>
25935
25936           This one shows how to bind to getter/setters:
25937
25938           <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
25939             <file name="index.html">
25940               <div ng-controller="ExampleController">
25941                 <form name="userForm">
25942                   <label>Name:
25943                     <input type="text" name="userName"
25944                            ng-model="user.name"
25945                            ng-model-options="{ getterSetter: true }" />
25946                   </label>
25947                 </form>
25948                 <pre>user.name = <span ng-bind="user.name()"></span></pre>
25949               </div>
25950             </file>
25951             <file name="app.js">
25952               angular.module('getterSetterExample', [])
25953                 .controller('ExampleController', ['$scope', function($scope) {
25954                   var _name = 'Brian';
25955                   $scope.user = {
25956                     name: function(newName) {
25957                       // Note that newName can be undefined for two reasons:
25958                       // 1. Because it is called as a getter and thus called with no arguments
25959                       // 2. Because the property should actually be set to undefined. This happens e.g. if the
25960                       //    input is invalid
25961                       return arguments.length ? (_name = newName) : _name;
25962                     }
25963                   };
25964                 }]);
25965             </file>
25966           </example>
25967          */
25968         var ngModelOptionsDirective = function() {
25969           return {
25970             restrict: 'A',
25971             controller: ['$scope', '$attrs', function($scope, $attrs) {
25972               var that = this;
25973               this.$options = copy($scope.$eval($attrs.ngModelOptions));
25974               // Allow adding/overriding bound events
25975               if (isDefined(this.$options.updateOn)) {
25976                 this.$options.updateOnDefault = false;
25977                 // extract "default" pseudo-event from list of events that can trigger a model update
25978                 this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
25979                   that.$options.updateOnDefault = true;
25980                   return ' ';
25981                 }));
25982               } else {
25983                 this.$options.updateOnDefault = true;
25984               }
25985             }]
25986           };
25987         };
25988
25989
25990
25991         // helper methods
25992         function addSetValidityMethod(context) {
25993           var ctrl = context.ctrl,
25994               $element = context.$element,
25995               classCache = {},
25996               set = context.set,
25997               unset = context.unset,
25998               $animate = context.$animate;
25999
26000           classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
26001
26002           ctrl.$setValidity = setValidity;
26003
26004           function setValidity(validationErrorKey, state, controller) {
26005             if (isUndefined(state)) {
26006               createAndSet('$pending', validationErrorKey, controller);
26007             } else {
26008               unsetAndCleanup('$pending', validationErrorKey, controller);
26009             }
26010             if (!isBoolean(state)) {
26011               unset(ctrl.$error, validationErrorKey, controller);
26012               unset(ctrl.$$success, validationErrorKey, controller);
26013             } else {
26014               if (state) {
26015                 unset(ctrl.$error, validationErrorKey, controller);
26016                 set(ctrl.$$success, validationErrorKey, controller);
26017               } else {
26018                 set(ctrl.$error, validationErrorKey, controller);
26019                 unset(ctrl.$$success, validationErrorKey, controller);
26020               }
26021             }
26022             if (ctrl.$pending) {
26023               cachedToggleClass(PENDING_CLASS, true);
26024               ctrl.$valid = ctrl.$invalid = undefined;
26025               toggleValidationCss('', null);
26026             } else {
26027               cachedToggleClass(PENDING_CLASS, false);
26028               ctrl.$valid = isObjectEmpty(ctrl.$error);
26029               ctrl.$invalid = !ctrl.$valid;
26030               toggleValidationCss('', ctrl.$valid);
26031             }
26032
26033             // re-read the state as the set/unset methods could have
26034             // combined state in ctrl.$error[validationError] (used for forms),
26035             // where setting/unsetting only increments/decrements the value,
26036             // and does not replace it.
26037             var combinedState;
26038             if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
26039               combinedState = undefined;
26040             } else if (ctrl.$error[validationErrorKey]) {
26041               combinedState = false;
26042             } else if (ctrl.$$success[validationErrorKey]) {
26043               combinedState = true;
26044             } else {
26045               combinedState = null;
26046             }
26047
26048             toggleValidationCss(validationErrorKey, combinedState);
26049             ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
26050           }
26051
26052           function createAndSet(name, value, controller) {
26053             if (!ctrl[name]) {
26054               ctrl[name] = {};
26055             }
26056             set(ctrl[name], value, controller);
26057           }
26058
26059           function unsetAndCleanup(name, value, controller) {
26060             if (ctrl[name]) {
26061               unset(ctrl[name], value, controller);
26062             }
26063             if (isObjectEmpty(ctrl[name])) {
26064               ctrl[name] = undefined;
26065             }
26066           }
26067
26068           function cachedToggleClass(className, switchValue) {
26069             if (switchValue && !classCache[className]) {
26070               $animate.addClass($element, className);
26071               classCache[className] = true;
26072             } else if (!switchValue && classCache[className]) {
26073               $animate.removeClass($element, className);
26074               classCache[className] = false;
26075             }
26076           }
26077
26078           function toggleValidationCss(validationErrorKey, isValid) {
26079             validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
26080
26081             cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
26082             cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
26083           }
26084         }
26085
26086         function isObjectEmpty(obj) {
26087           if (obj) {
26088             for (var prop in obj) {
26089               if (obj.hasOwnProperty(prop)) {
26090                 return false;
26091               }
26092             }
26093           }
26094           return true;
26095         }
26096
26097         /**
26098          * @ngdoc directive
26099          * @name ngNonBindable
26100          * @restrict AC
26101          * @priority 1000
26102          *
26103          * @description
26104          * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
26105          * DOM element. This is useful if the element contains what appears to be Angular directives and
26106          * bindings but which should be ignored by Angular. This could be the case if you have a site that
26107          * displays snippets of code, for instance.
26108          *
26109          * @element ANY
26110          *
26111          * @example
26112          * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
26113          * but the one wrapped in `ngNonBindable` is left alone.
26114          *
26115          * @example
26116             <example>
26117               <file name="index.html">
26118                 <div>Normal: {{1 + 2}}</div>
26119                 <div ng-non-bindable>Ignored: {{1 + 2}}</div>
26120               </file>
26121               <file name="protractor.js" type="protractor">
26122                it('should check ng-non-bindable', function() {
26123                  expect(element(by.binding('1 + 2')).getText()).toContain('3');
26124                  expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
26125                });
26126               </file>
26127             </example>
26128          */
26129         var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
26130
26131         /* global jqLiteRemove */
26132
26133         var ngOptionsMinErr = minErr('ngOptions');
26134
26135         /**
26136          * @ngdoc directive
26137          * @name ngOptions
26138          * @restrict A
26139          *
26140          * @description
26141          *
26142          * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
26143          * elements for the `<select>` element using the array or object obtained by evaluating the
26144          * `ngOptions` comprehension expression.
26145          *
26146          * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
26147          * similar result. However, `ngOptions` provides some benefits such as reducing memory and
26148          * increasing speed by not creating a new scope for each repeated instance, as well as providing
26149          * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
26150          * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
26151          *  to a non-string value. This is because an option element can only be bound to string values at
26152          * present.
26153          *
26154          * When an item in the `<select>` menu is selected, the array element or object property
26155          * represented by the selected option will be bound to the model identified by the `ngModel`
26156          * directive.
26157          *
26158          * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
26159          * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
26160          * option. See example below for demonstration.
26161          *
26162          * ## Complex Models (objects or collections)
26163          *
26164          * By default, `ngModel` watches the model by reference, not value. This is important to know when
26165          * binding the select to a model that is an object or a collection.
26166          *
26167          * One issue occurs if you want to preselect an option. For example, if you set
26168          * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
26169          * because the objects are not identical. So by default, you should always reference the item in your collection
26170          * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
26171          *
26172          * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
26173          * of the item not by reference, but by the result of the `track by` expression. For example, if your
26174          * collection items have an id property, you would `track by item.id`.
26175          *
26176          * A different issue with objects or collections is that ngModel won't detect if an object property or
26177          * a collection item changes. For that reason, `ngOptions` additionally watches the model using
26178          * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
26179          * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
26180          * has not changed identity, but only a property on the object or an item in the collection changes.
26181          *
26182          * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
26183          * if the model is an array). This means that changing a property deeper than the first level inside the
26184          * object/collection will not trigger a re-rendering.
26185          *
26186          * ## `select` **`as`**
26187          *
26188          * Using `select` **`as`** will bind the result of the `select` expression to the model, but
26189          * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
26190          * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
26191          * is used, the result of that expression will be set as the value of the `option` and `select` elements.
26192          *
26193          *
26194          * ### `select` **`as`** and **`track by`**
26195          *
26196          * <div class="alert alert-warning">
26197          * Be careful when using `select` **`as`** and **`track by`** in the same expression.
26198          * </div>
26199          *
26200          * Given this array of items on the $scope:
26201          *
26202          * ```js
26203          * $scope.items = [{
26204          *   id: 1,
26205          *   label: 'aLabel',
26206          *   subItem: { name: 'aSubItem' }
26207          * }, {
26208          *   id: 2,
26209          *   label: 'bLabel',
26210          *   subItem: { name: 'bSubItem' }
26211          * }];
26212          * ```
26213          *
26214          * This will work:
26215          *
26216          * ```html
26217          * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
26218          * ```
26219          * ```js
26220          * $scope.selected = $scope.items[0];
26221          * ```
26222          *
26223          * but this will not work:
26224          *
26225          * ```html
26226          * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
26227          * ```
26228          * ```js
26229          * $scope.selected = $scope.items[0].subItem;
26230          * ```
26231          *
26232          * In both examples, the **`track by`** expression is applied successfully to each `item` in the
26233          * `items` array. Because the selected option has been set programmatically in the controller, the
26234          * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
26235          * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
26236          * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
26237          * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
26238          * is not matched against any `<option>` and the `<select>` appears as having no selected value.
26239          *
26240          *
26241          * @param {string} ngModel Assignable angular expression to data-bind to.
26242          * @param {string=} name Property name of the form under which the control is published.
26243          * @param {string=} required The control is considered valid only if value is entered.
26244          * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26245          *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26246          *    `required` when you want to data-bind to the `required` attribute.
26247          * @param {comprehension_expression=} ngOptions in one of the following forms:
26248          *
26249          *   * for array data sources:
26250          *     * `label` **`for`** `value` **`in`** `array`
26251          *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
26252          *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
26253          *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
26254          *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26255          *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26256          *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
26257          *        (for including a filter with `track by`)
26258          *   * for object data sources:
26259          *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26260          *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26261          *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
26262          *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
26263          *     * `select` **`as`** `label` **`group by`** `group`
26264          *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26265          *     * `select` **`as`** `label` **`disable when`** `disable`
26266          *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26267          *
26268          * Where:
26269          *
26270          *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
26271          *   * `value`: local variable which will refer to each item in the `array` or each property value
26272          *      of `object` during iteration.
26273          *   * `key`: local variable which will refer to a property name in `object` during iteration.
26274          *   * `label`: The result of this expression will be the label for `<option>` element. The
26275          *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
26276          *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
26277          *      element. If not specified, `select` expression will default to `value`.
26278          *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
26279          *      DOM element.
26280          *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
26281          *      element. Return `true` to disable.
26282          *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
26283          *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
26284          *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
26285          *      even when the options are recreated (e.g. reloaded from the server).
26286          *
26287          * @example
26288             <example module="selectExample">
26289               <file name="index.html">
26290                 <script>
26291                 angular.module('selectExample', [])
26292                   .controller('ExampleController', ['$scope', function($scope) {
26293                     $scope.colors = [
26294                       {name:'black', shade:'dark'},
26295                       {name:'white', shade:'light', notAnOption: true},
26296                       {name:'red', shade:'dark'},
26297                       {name:'blue', shade:'dark', notAnOption: true},
26298                       {name:'yellow', shade:'light', notAnOption: false}
26299                     ];
26300                     $scope.myColor = $scope.colors[2]; // red
26301                   }]);
26302                 </script>
26303                 <div ng-controller="ExampleController">
26304                   <ul>
26305                     <li ng-repeat="color in colors">
26306                       <label>Name: <input ng-model="color.name"></label>
26307                       <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
26308                       <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
26309                     </li>
26310                     <li>
26311                       <button ng-click="colors.push({})">add</button>
26312                     </li>
26313                   </ul>
26314                   <hr/>
26315                   <label>Color (null not allowed):
26316                     <select ng-model="myColor" ng-options="color.name for color in colors"></select>
26317                   </label><br/>
26318                   <label>Color (null allowed):
26319                   <span  class="nullable">
26320                     <select ng-model="myColor" ng-options="color.name for color in colors">
26321                       <option value="">-- choose color --</option>
26322                     </select>
26323                   </span></label><br/>
26324
26325                   <label>Color grouped by shade:
26326                     <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
26327                     </select>
26328                   </label><br/>
26329
26330                   <label>Color grouped by shade, with some disabled:
26331                     <select ng-model="myColor"
26332                           ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
26333                     </select>
26334                   </label><br/>
26335
26336
26337
26338                   Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
26339                   <br/>
26340                   <hr/>
26341                   Currently selected: {{ {selected_color:myColor} }}
26342                   <div style="border:solid 1px black; height:20px"
26343                        ng-style="{'background-color':myColor.name}">
26344                   </div>
26345                 </div>
26346               </file>
26347               <file name="protractor.js" type="protractor">
26348                  it('should check ng-options', function() {
26349                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
26350                    element.all(by.model('myColor')).first().click();
26351                    element.all(by.css('select[ng-model="myColor"] option')).first().click();
26352                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
26353                    element(by.css('.nullable select[ng-model="myColor"]')).click();
26354                    element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
26355                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
26356                  });
26357               </file>
26358             </example>
26359          */
26360
26361         // jshint maxlen: false
26362         //                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
26363         var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
26364                                 // 1: value expression (valueFn)
26365                                 // 2: label expression (displayFn)
26366                                 // 3: group by expression (groupByFn)
26367                                 // 4: disable when expression (disableWhenFn)
26368                                 // 5: array item variable name
26369                                 // 6: object item key variable name
26370                                 // 7: object item value variable name
26371                                 // 8: collection expression
26372                                 // 9: track by expression
26373         // jshint maxlen: 100
26374
26375
26376         var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26377
26378           function parseOptionsExpression(optionsExp, selectElement, scope) {
26379
26380             var match = optionsExp.match(NG_OPTIONS_REGEXP);
26381             if (!(match)) {
26382               throw ngOptionsMinErr('iexp',
26383                 "Expected expression in form of " +
26384                 "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
26385                 " but got '{0}'. Element: {1}",
26386                 optionsExp, startingTag(selectElement));
26387             }
26388
26389             // Extract the parts from the ngOptions expression
26390
26391             // The variable name for the value of the item in the collection
26392             var valueName = match[5] || match[7];
26393             // The variable name for the key of the item in the collection
26394             var keyName = match[6];
26395
26396             // An expression that generates the viewValue for an option if there is a label expression
26397             var selectAs = / as /.test(match[0]) && match[1];
26398             // An expression that is used to track the id of each object in the options collection
26399             var trackBy = match[9];
26400             // An expression that generates the viewValue for an option if there is no label expression
26401             var valueFn = $parse(match[2] ? match[1] : valueName);
26402             var selectAsFn = selectAs && $parse(selectAs);
26403             var viewValueFn = selectAsFn || valueFn;
26404             var trackByFn = trackBy && $parse(trackBy);
26405
26406             // Get the value by which we are going to track the option
26407             // if we have a trackFn then use that (passing scope and locals)
26408             // otherwise just hash the given viewValue
26409             var getTrackByValueFn = trackBy ?
26410                                       function(value, locals) { return trackByFn(scope, locals); } :
26411                                       function getHashOfValue(value) { return hashKey(value); };
26412             var getTrackByValue = function(value, key) {
26413               return getTrackByValueFn(value, getLocals(value, key));
26414             };
26415
26416             var displayFn = $parse(match[2] || match[1]);
26417             var groupByFn = $parse(match[3] || '');
26418             var disableWhenFn = $parse(match[4] || '');
26419             var valuesFn = $parse(match[8]);
26420
26421             var locals = {};
26422             var getLocals = keyName ? function(value, key) {
26423               locals[keyName] = key;
26424               locals[valueName] = value;
26425               return locals;
26426             } : function(value) {
26427               locals[valueName] = value;
26428               return locals;
26429             };
26430
26431
26432             function Option(selectValue, viewValue, label, group, disabled) {
26433               this.selectValue = selectValue;
26434               this.viewValue = viewValue;
26435               this.label = label;
26436               this.group = group;
26437               this.disabled = disabled;
26438             }
26439
26440             function getOptionValuesKeys(optionValues) {
26441               var optionValuesKeys;
26442
26443               if (!keyName && isArrayLike(optionValues)) {
26444                 optionValuesKeys = optionValues;
26445               } else {
26446                 // if object, extract keys, in enumeration order, unsorted
26447                 optionValuesKeys = [];
26448                 for (var itemKey in optionValues) {
26449                   if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
26450                     optionValuesKeys.push(itemKey);
26451                   }
26452                 }
26453               }
26454               return optionValuesKeys;
26455             }
26456
26457             return {
26458               trackBy: trackBy,
26459               getTrackByValue: getTrackByValue,
26460               getWatchables: $parse(valuesFn, function(optionValues) {
26461                 // Create a collection of things that we would like to watch (watchedArray)
26462                 // so that they can all be watched using a single $watchCollection
26463                 // that only runs the handler once if anything changes
26464                 var watchedArray = [];
26465                 optionValues = optionValues || [];
26466
26467                 var optionValuesKeys = getOptionValuesKeys(optionValues);
26468                 var optionValuesLength = optionValuesKeys.length;
26469                 for (var index = 0; index < optionValuesLength; index++) {
26470                   var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
26471                   var value = optionValues[key];
26472
26473                   var locals = getLocals(optionValues[key], key);
26474                   var selectValue = getTrackByValueFn(optionValues[key], locals);
26475                   watchedArray.push(selectValue);
26476
26477                   // Only need to watch the displayFn if there is a specific label expression
26478                   if (match[2] || match[1]) {
26479                     var label = displayFn(scope, locals);
26480                     watchedArray.push(label);
26481                   }
26482
26483                   // Only need to watch the disableWhenFn if there is a specific disable expression
26484                   if (match[4]) {
26485                     var disableWhen = disableWhenFn(scope, locals);
26486                     watchedArray.push(disableWhen);
26487                   }
26488                 }
26489                 return watchedArray;
26490               }),
26491
26492               getOptions: function() {
26493
26494                 var optionItems = [];
26495                 var selectValueMap = {};
26496
26497                 // The option values were already computed in the `getWatchables` fn,
26498                 // which must have been called to trigger `getOptions`
26499                 var optionValues = valuesFn(scope) || [];
26500                 var optionValuesKeys = getOptionValuesKeys(optionValues);
26501                 var optionValuesLength = optionValuesKeys.length;
26502
26503                 for (var index = 0; index < optionValuesLength; index++) {
26504                   var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
26505                   var value = optionValues[key];
26506                   var locals = getLocals(value, key);
26507                   var viewValue = viewValueFn(scope, locals);
26508                   var selectValue = getTrackByValueFn(viewValue, locals);
26509                   var label = displayFn(scope, locals);
26510                   var group = groupByFn(scope, locals);
26511                   var disabled = disableWhenFn(scope, locals);
26512                   var optionItem = new Option(selectValue, viewValue, label, group, disabled);
26513
26514                   optionItems.push(optionItem);
26515                   selectValueMap[selectValue] = optionItem;
26516                 }
26517
26518                 return {
26519                   items: optionItems,
26520                   selectValueMap: selectValueMap,
26521                   getOptionFromViewValue: function(value) {
26522                     return selectValueMap[getTrackByValue(value)];
26523                   },
26524                   getViewValueFromOption: function(option) {
26525                     // If the viewValue could be an object that may be mutated by the application,
26526                     // we need to make a copy and not return the reference to the value on the option.
26527                     return trackBy ? angular.copy(option.viewValue) : option.viewValue;
26528                   }
26529                 };
26530               }
26531             };
26532           }
26533
26534
26535           // we can't just jqLite('<option>') since jqLite is not smart enough
26536           // to create it in <select> and IE barfs otherwise.
26537           var optionTemplate = document.createElement('option'),
26538               optGroupTemplate = document.createElement('optgroup');
26539
26540
26541             function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
26542
26543               // if ngModel is not defined, we don't need to do anything
26544               var ngModelCtrl = ctrls[1];
26545               if (!ngModelCtrl) return;
26546
26547               var selectCtrl = ctrls[0];
26548               var multiple = attr.multiple;
26549
26550               // The emptyOption allows the application developer to provide their own custom "empty"
26551               // option when the viewValue does not match any of the option values.
26552               var emptyOption;
26553               for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
26554                 if (children[i].value === '') {
26555                   emptyOption = children.eq(i);
26556                   break;
26557                 }
26558               }
26559
26560               var providedEmptyOption = !!emptyOption;
26561
26562               var unknownOption = jqLite(optionTemplate.cloneNode(false));
26563               unknownOption.val('?');
26564
26565               var options;
26566               var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
26567
26568
26569               var renderEmptyOption = function() {
26570                 if (!providedEmptyOption) {
26571                   selectElement.prepend(emptyOption);
26572                 }
26573                 selectElement.val('');
26574                 emptyOption.prop('selected', true); // needed for IE
26575                 emptyOption.attr('selected', true);
26576               };
26577
26578               var removeEmptyOption = function() {
26579                 if (!providedEmptyOption) {
26580                   emptyOption.remove();
26581                 }
26582               };
26583
26584
26585               var renderUnknownOption = function() {
26586                 selectElement.prepend(unknownOption);
26587                 selectElement.val('?');
26588                 unknownOption.prop('selected', true); // needed for IE
26589                 unknownOption.attr('selected', true);
26590               };
26591
26592               var removeUnknownOption = function() {
26593                 unknownOption.remove();
26594               };
26595
26596               // Update the controller methods for multiple selectable options
26597               if (!multiple) {
26598
26599                 selectCtrl.writeValue = function writeNgOptionsValue(value) {
26600                   var option = options.getOptionFromViewValue(value);
26601
26602                   if (option && !option.disabled) {
26603                     if (selectElement[0].value !== option.selectValue) {
26604                       removeUnknownOption();
26605                       removeEmptyOption();
26606
26607                       selectElement[0].value = option.selectValue;
26608                       option.element.selected = true;
26609                       option.element.setAttribute('selected', 'selected');
26610                     }
26611                   } else {
26612                     if (value === null || providedEmptyOption) {
26613                       removeUnknownOption();
26614                       renderEmptyOption();
26615                     } else {
26616                       removeEmptyOption();
26617                       renderUnknownOption();
26618                     }
26619                   }
26620                 };
26621
26622                 selectCtrl.readValue = function readNgOptionsValue() {
26623
26624                   var selectedOption = options.selectValueMap[selectElement.val()];
26625
26626                   if (selectedOption && !selectedOption.disabled) {
26627                     removeEmptyOption();
26628                     removeUnknownOption();
26629                     return options.getViewValueFromOption(selectedOption);
26630                   }
26631                   return null;
26632                 };
26633
26634                 // If we are using `track by` then we must watch the tracked value on the model
26635                 // since ngModel only watches for object identity change
26636                 if (ngOptions.trackBy) {
26637                   scope.$watch(
26638                     function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
26639                     function() { ngModelCtrl.$render(); }
26640                   );
26641                 }
26642
26643               } else {
26644
26645                 ngModelCtrl.$isEmpty = function(value) {
26646                   return !value || value.length === 0;
26647                 };
26648
26649
26650                 selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
26651                   options.items.forEach(function(option) {
26652                     option.element.selected = false;
26653                   });
26654
26655                   if (value) {
26656                     value.forEach(function(item) {
26657                       var option = options.getOptionFromViewValue(item);
26658                       if (option && !option.disabled) option.element.selected = true;
26659                     });
26660                   }
26661                 };
26662
26663
26664                 selectCtrl.readValue = function readNgOptionsMultiple() {
26665                   var selectedValues = selectElement.val() || [],
26666                       selections = [];
26667
26668                   forEach(selectedValues, function(value) {
26669                     var option = options.selectValueMap[value];
26670                     if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
26671                   });
26672
26673                   return selections;
26674                 };
26675
26676                 // If we are using `track by` then we must watch these tracked values on the model
26677                 // since ngModel only watches for object identity change
26678                 if (ngOptions.trackBy) {
26679
26680                   scope.$watchCollection(function() {
26681                     if (isArray(ngModelCtrl.$viewValue)) {
26682                       return ngModelCtrl.$viewValue.map(function(value) {
26683                         return ngOptions.getTrackByValue(value);
26684                       });
26685                     }
26686                   }, function() {
26687                     ngModelCtrl.$render();
26688                   });
26689
26690                 }
26691               }
26692
26693
26694               if (providedEmptyOption) {
26695
26696                 // we need to remove it before calling selectElement.empty() because otherwise IE will
26697                 // remove the label from the element. wtf?
26698                 emptyOption.remove();
26699
26700                 // compile the element since there might be bindings in it
26701                 $compile(emptyOption)(scope);
26702
26703                 // remove the class, which is added automatically because we recompile the element and it
26704                 // becomes the compilation root
26705                 emptyOption.removeClass('ng-scope');
26706               } else {
26707                 emptyOption = jqLite(optionTemplate.cloneNode(false));
26708               }
26709
26710               // We need to do this here to ensure that the options object is defined
26711               // when we first hit it in writeNgOptionsValue
26712               updateOptions();
26713
26714               // We will re-render the option elements if the option values or labels change
26715               scope.$watchCollection(ngOptions.getWatchables, updateOptions);
26716
26717               // ------------------------------------------------------------------ //
26718
26719
26720               function updateOptionElement(option, element) {
26721                 option.element = element;
26722                 element.disabled = option.disabled;
26723                 // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
26724                 // selects in certain circumstances when multiple selects are next to each other and display
26725                 // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
26726                 // See https://github.com/angular/angular.js/issues/11314 for more info.
26727                 // This is unfortunately untestable with unit / e2e tests
26728                 if (option.label !== element.label) {
26729                   element.label = option.label;
26730                   element.textContent = option.label;
26731                 }
26732                 if (option.value !== element.value) element.value = option.selectValue;
26733               }
26734
26735               function addOrReuseElement(parent, current, type, templateElement) {
26736                 var element;
26737                 // Check whether we can reuse the next element
26738                 if (current && lowercase(current.nodeName) === type) {
26739                   // The next element is the right type so reuse it
26740                   element = current;
26741                 } else {
26742                   // The next element is not the right type so create a new one
26743                   element = templateElement.cloneNode(false);
26744                   if (!current) {
26745                     // There are no more elements so just append it to the select
26746                     parent.appendChild(element);
26747                   } else {
26748                     // The next element is not a group so insert the new one
26749                     parent.insertBefore(element, current);
26750                   }
26751                 }
26752                 return element;
26753               }
26754
26755
26756               function removeExcessElements(current) {
26757                 var next;
26758                 while (current) {
26759                   next = current.nextSibling;
26760                   jqLiteRemove(current);
26761                   current = next;
26762                 }
26763               }
26764
26765
26766               function skipEmptyAndUnknownOptions(current) {
26767                 var emptyOption_ = emptyOption && emptyOption[0];
26768                 var unknownOption_ = unknownOption && unknownOption[0];
26769
26770                 // We cannot rely on the extracted empty option being the same as the compiled empty option,
26771                 // because the compiled empty option might have been replaced by a comment because
26772                 // it had an "element" transclusion directive on it (such as ngIf)
26773                 if (emptyOption_ || unknownOption_) {
26774                   while (current &&
26775                         (current === emptyOption_ ||
26776                         current === unknownOption_ ||
26777                         current.nodeType === NODE_TYPE_COMMENT ||
26778                         current.value === '')) {
26779                     current = current.nextSibling;
26780                   }
26781                 }
26782                 return current;
26783               }
26784
26785
26786               function updateOptions() {
26787
26788                 var previousValue = options && selectCtrl.readValue();
26789
26790                 options = ngOptions.getOptions();
26791
26792                 var groupMap = {};
26793                 var currentElement = selectElement[0].firstChild;
26794
26795                 // Ensure that the empty option is always there if it was explicitly provided
26796                 if (providedEmptyOption) {
26797                   selectElement.prepend(emptyOption);
26798                 }
26799
26800                 currentElement = skipEmptyAndUnknownOptions(currentElement);
26801
26802                 options.items.forEach(function updateOption(option) {
26803                   var group;
26804                   var groupElement;
26805                   var optionElement;
26806
26807                   if (option.group) {
26808
26809                     // This option is to live in a group
26810                     // See if we have already created this group
26811                     group = groupMap[option.group];
26812
26813                     if (!group) {
26814
26815                       // We have not already created this group
26816                       groupElement = addOrReuseElement(selectElement[0],
26817                                                        currentElement,
26818                                                        'optgroup',
26819                                                        optGroupTemplate);
26820                       // Move to the next element
26821                       currentElement = groupElement.nextSibling;
26822
26823                       // Update the label on the group element
26824                       groupElement.label = option.group;
26825
26826                       // Store it for use later
26827                       group = groupMap[option.group] = {
26828                         groupElement: groupElement,
26829                         currentOptionElement: groupElement.firstChild
26830                       };
26831
26832                     }
26833
26834                     // So now we have a group for this option we add the option to the group
26835                     optionElement = addOrReuseElement(group.groupElement,
26836                                                       group.currentOptionElement,
26837                                                       'option',
26838                                                       optionTemplate);
26839                     updateOptionElement(option, optionElement);
26840                     // Move to the next element
26841                     group.currentOptionElement = optionElement.nextSibling;
26842
26843                   } else {
26844
26845                     // This option is not in a group
26846                     optionElement = addOrReuseElement(selectElement[0],
26847                                                       currentElement,
26848                                                       'option',
26849                                                       optionTemplate);
26850                     updateOptionElement(option, optionElement);
26851                     // Move to the next element
26852                     currentElement = optionElement.nextSibling;
26853                   }
26854                 });
26855
26856
26857                 // Now remove all excess options and group
26858                 Object.keys(groupMap).forEach(function(key) {
26859                   removeExcessElements(groupMap[key].currentOptionElement);
26860                 });
26861                 removeExcessElements(currentElement);
26862
26863                 ngModelCtrl.$render();
26864
26865                 // Check to see if the value has changed due to the update to the options
26866                 if (!ngModelCtrl.$isEmpty(previousValue)) {
26867                   var nextValue = selectCtrl.readValue();
26868                   if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
26869                     ngModelCtrl.$setViewValue(nextValue);
26870                     ngModelCtrl.$render();
26871                   }
26872                 }
26873
26874               }
26875           }
26876
26877           return {
26878             restrict: 'A',
26879             terminal: true,
26880             require: ['select', '?ngModel'],
26881             link: {
26882               pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
26883                 // Deactivate the SelectController.register method to prevent
26884                 // option directives from accidentally registering themselves
26885                 // (and unwanted $destroy handlers etc.)
26886                 ctrls[0].registerOption = noop;
26887               },
26888               post: ngOptionsPostLink
26889             }
26890           };
26891         }];
26892
26893         /**
26894          * @ngdoc directive
26895          * @name ngPluralize
26896          * @restrict EA
26897          *
26898          * @description
26899          * `ngPluralize` is a directive that displays messages according to en-US localization rules.
26900          * These rules are bundled with angular.js, but can be overridden
26901          * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
26902          * by specifying the mappings between
26903          * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26904          * and the strings to be displayed.
26905          *
26906          * # Plural categories and explicit number rules
26907          * There are two
26908          * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26909          * in Angular's default en-US locale: "one" and "other".
26910          *
26911          * While a plural category may match many numbers (for example, in en-US locale, "other" can match
26912          * any number that is not 1), an explicit number rule can only match one number. For example, the
26913          * explicit number rule for "3" matches the number 3. There are examples of plural categories
26914          * and explicit number rules throughout the rest of this documentation.
26915          *
26916          * # Configuring ngPluralize
26917          * You configure ngPluralize by providing 2 attributes: `count` and `when`.
26918          * You can also provide an optional attribute, `offset`.
26919          *
26920          * The value of the `count` attribute can be either a string or an {@link guide/expression
26921          * Angular expression}; these are evaluated on the current scope for its bound value.
26922          *
26923          * The `when` attribute specifies the mappings between plural categories and the actual
26924          * string to be displayed. The value of the attribute should be a JSON object.
26925          *
26926          * The following example shows how to configure ngPluralize:
26927          *
26928          * ```html
26929          * <ng-pluralize count="personCount"
26930                          when="{'0': 'Nobody is viewing.',
26931          *                      'one': '1 person is viewing.',
26932          *                      'other': '{} people are viewing.'}">
26933          * </ng-pluralize>
26934          *```
26935          *
26936          * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
26937          * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
26938          * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
26939          * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
26940          * show "a dozen people are viewing".
26941          *
26942          * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
26943          * into pluralized strings. In the previous example, Angular will replace `{}` with
26944          * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
26945          * for <span ng-non-bindable>{{numberExpression}}</span>.
26946          *
26947          * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
26948          * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
26949          *
26950          * # Configuring ngPluralize with offset
26951          * The `offset` attribute allows further customization of pluralized text, which can result in
26952          * a better user experience. For example, instead of the message "4 people are viewing this document",
26953          * you might display "John, Kate and 2 others are viewing this document".
26954          * The offset attribute allows you to offset a number by any desired value.
26955          * Let's take a look at an example:
26956          *
26957          * ```html
26958          * <ng-pluralize count="personCount" offset=2
26959          *               when="{'0': 'Nobody is viewing.',
26960          *                      '1': '{{person1}} is viewing.',
26961          *                      '2': '{{person1}} and {{person2}} are viewing.',
26962          *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
26963          *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
26964          * </ng-pluralize>
26965          * ```
26966          *
26967          * Notice that we are still using two plural categories(one, other), but we added
26968          * three explicit number rules 0, 1 and 2.
26969          * When one person, perhaps John, views the document, "John is viewing" will be shown.
26970          * When three people view the document, no explicit number rule is found, so
26971          * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
26972          * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
26973          * is shown.
26974          *
26975          * Note that when you specify offsets, you must provide explicit number rules for
26976          * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
26977          * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
26978          * plural categories "one" and "other".
26979          *
26980          * @param {string|expression} count The variable to be bound to.
26981          * @param {string} when The mapping between plural category to its corresponding strings.
26982          * @param {number=} offset Offset to deduct from the total number.
26983          *
26984          * @example
26985             <example module="pluralizeExample">
26986               <file name="index.html">
26987                 <script>
26988                   angular.module('pluralizeExample', [])
26989                     .controller('ExampleController', ['$scope', function($scope) {
26990                       $scope.person1 = 'Igor';
26991                       $scope.person2 = 'Misko';
26992                       $scope.personCount = 1;
26993                     }]);
26994                 </script>
26995                 <div ng-controller="ExampleController">
26996                   <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
26997                   <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
26998                   <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
26999
27000                   <!--- Example with simple pluralization rules for en locale --->
27001                   Without Offset:
27002                   <ng-pluralize count="personCount"
27003                                 when="{'0': 'Nobody is viewing.',
27004                                        'one': '1 person is viewing.',
27005                                        'other': '{} people are viewing.'}">
27006                   </ng-pluralize><br>
27007
27008                   <!--- Example with offset --->
27009                   With Offset(2):
27010                   <ng-pluralize count="personCount" offset=2
27011                                 when="{'0': 'Nobody is viewing.',
27012                                        '1': '{{person1}} is viewing.',
27013                                        '2': '{{person1}} and {{person2}} are viewing.',
27014                                        'one': '{{person1}}, {{person2}} and one other person are viewing.',
27015                                        'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
27016                   </ng-pluralize>
27017                 </div>
27018               </file>
27019               <file name="protractor.js" type="protractor">
27020                 it('should show correct pluralized string', function() {
27021                   var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
27022                   var withOffset = element.all(by.css('ng-pluralize')).get(1);
27023                   var countInput = element(by.model('personCount'));
27024
27025                   expect(withoutOffset.getText()).toEqual('1 person is viewing.');
27026                   expect(withOffset.getText()).toEqual('Igor is viewing.');
27027
27028                   countInput.clear();
27029                   countInput.sendKeys('0');
27030
27031                   expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
27032                   expect(withOffset.getText()).toEqual('Nobody is viewing.');
27033
27034                   countInput.clear();
27035                   countInput.sendKeys('2');
27036
27037                   expect(withoutOffset.getText()).toEqual('2 people are viewing.');
27038                   expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
27039
27040                   countInput.clear();
27041                   countInput.sendKeys('3');
27042
27043                   expect(withoutOffset.getText()).toEqual('3 people are viewing.');
27044                   expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
27045
27046                   countInput.clear();
27047                   countInput.sendKeys('4');
27048
27049                   expect(withoutOffset.getText()).toEqual('4 people are viewing.');
27050                   expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
27051                 });
27052                 it('should show data-bound names', function() {
27053                   var withOffset = element.all(by.css('ng-pluralize')).get(1);
27054                   var personCount = element(by.model('personCount'));
27055                   var person1 = element(by.model('person1'));
27056                   var person2 = element(by.model('person2'));
27057                   personCount.clear();
27058                   personCount.sendKeys('4');
27059                   person1.clear();
27060                   person1.sendKeys('Di');
27061                   person2.clear();
27062                   person2.sendKeys('Vojta');
27063                   expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
27064                 });
27065               </file>
27066             </example>
27067          */
27068         var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
27069           var BRACE = /{}/g,
27070               IS_WHEN = /^when(Minus)?(.+)$/;
27071
27072           return {
27073             link: function(scope, element, attr) {
27074               var numberExp = attr.count,
27075                   whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
27076                   offset = attr.offset || 0,
27077                   whens = scope.$eval(whenExp) || {},
27078                   whensExpFns = {},
27079                   startSymbol = $interpolate.startSymbol(),
27080                   endSymbol = $interpolate.endSymbol(),
27081                   braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
27082                   watchRemover = angular.noop,
27083                   lastCount;
27084
27085               forEach(attr, function(expression, attributeName) {
27086                 var tmpMatch = IS_WHEN.exec(attributeName);
27087                 if (tmpMatch) {
27088                   var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
27089                   whens[whenKey] = element.attr(attr.$attr[attributeName]);
27090                 }
27091               });
27092               forEach(whens, function(expression, key) {
27093                 whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
27094
27095               });
27096
27097               scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
27098                 var count = parseFloat(newVal);
27099                 var countIsNaN = isNaN(count);
27100
27101                 if (!countIsNaN && !(count in whens)) {
27102                   // If an explicit number rule such as 1, 2, 3... is defined, just use it.
27103                   // Otherwise, check it against pluralization rules in $locale service.
27104                   count = $locale.pluralCat(count - offset);
27105                 }
27106
27107                 // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
27108                 // In JS `NaN !== NaN`, so we have to exlicitly check.
27109                 if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
27110                   watchRemover();
27111                   var whenExpFn = whensExpFns[count];
27112                   if (isUndefined(whenExpFn)) {
27113                     if (newVal != null) {
27114                       $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
27115                     }
27116                     watchRemover = noop;
27117                     updateElementText();
27118                   } else {
27119                     watchRemover = scope.$watch(whenExpFn, updateElementText);
27120                   }
27121                   lastCount = count;
27122                 }
27123               });
27124
27125               function updateElementText(newText) {
27126                 element.text(newText || '');
27127               }
27128             }
27129           };
27130         }];
27131
27132         /**
27133          * @ngdoc directive
27134          * @name ngRepeat
27135          * @multiElement
27136          *
27137          * @description
27138          * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
27139          * instance gets its own scope, where the given loop variable is set to the current collection item,
27140          * and `$index` is set to the item index or key.
27141          *
27142          * Special properties are exposed on the local scope of each template instance, including:
27143          *
27144          * | Variable  | Type            | Details                                                                     |
27145          * |-----------|-----------------|-----------------------------------------------------------------------------|
27146          * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
27147          * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
27148          * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
27149          * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
27150          * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
27151          * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
27152          *
27153          * <div class="alert alert-info">
27154          *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
27155          *   This may be useful when, for instance, nesting ngRepeats.
27156          * </div>
27157          *
27158          *
27159          * # Iterating over object properties
27160          *
27161          * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
27162          * syntax:
27163          *
27164          * ```js
27165          * <div ng-repeat="(key, value) in myObj"> ... </div>
27166          * ```
27167          *
27168          * You need to be aware that the JavaScript specification does not define the order of keys
27169          * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
27170          * used to sort the keys alphabetically.)
27171          *
27172          * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
27173          * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
27174          * keys in the order in which they were defined, although there are exceptions when keys are deleted
27175          * and reinstated. See the [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
27176          *
27177          * If this is not desired, the recommended workaround is to convert your object into an array
27178          * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
27179          * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
27180          * or implement a `$watch` on the object yourself.
27181          *
27182          *
27183          * # Tracking and Duplicates
27184          *
27185          * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
27186          * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
27187          *
27188          * * When an item is added, a new instance of the template is added to the DOM.
27189          * * When an item is removed, its template instance is removed from the DOM.
27190          * * When items are reordered, their respective templates are reordered in the DOM.
27191          *
27192          * To minimize creation of DOM elements, `ngRepeat` uses a function
27193          * to "keep track" of all items in the collection and their corresponding DOM elements.
27194          * For example, if an item is added to the collection, ngRepeat will know that all other items
27195          * already have DOM elements, and will not re-render them.
27196          *
27197          * The default tracking function (which tracks items by their identity) does not allow
27198          * duplicate items in arrays. This is because when there are duplicates, it is not possible
27199          * to maintain a one-to-one mapping between collection items and DOM elements.
27200          *
27201          * If you do need to repeat duplicate items, you can substitute the default tracking behavior
27202          * with your own using the `track by` expression.
27203          *
27204          * For example, you may track items by the index of each item in the collection, using the
27205          * special scope property `$index`:
27206          * ```html
27207          *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
27208          *      {{n}}
27209          *    </div>
27210          * ```
27211          *
27212          * You may also use arbitrary expressions in `track by`, including references to custom functions
27213          * on the scope:
27214          * ```html
27215          *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
27216          *      {{n}}
27217          *    </div>
27218          * ```
27219          *
27220          * <div class="alert alert-success">
27221          * If you are working with objects that have an identifier property, you should track
27222          * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
27223          * will not have to rebuild the DOM elements for items it has already rendered, even if the
27224          * JavaScript objects in the collection have been substituted for new ones. For large collections,
27225          * this signifincantly improves rendering performance. If you don't have a unique identifier,
27226          * `track by $index` can also provide a performance boost.
27227          * </div>
27228          * ```html
27229          *    <div ng-repeat="model in collection track by model.id">
27230          *      {{model.name}}
27231          *    </div>
27232          * ```
27233          *
27234          * When no `track by` expression is provided, it is equivalent to tracking by the built-in
27235          * `$id` function, which tracks items by their identity:
27236          * ```html
27237          *    <div ng-repeat="obj in collection track by $id(obj)">
27238          *      {{obj.prop}}
27239          *    </div>
27240          * ```
27241          *
27242          * <div class="alert alert-warning">
27243          * **Note:** `track by` must always be the last expression:
27244          * </div>
27245          * ```
27246          * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
27247          *     {{model.name}}
27248          * </div>
27249          * ```
27250          *
27251          * # Special repeat start and end points
27252          * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
27253          * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
27254          * 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)
27255          * up to and including the ending HTML tag where **ng-repeat-end** is placed.
27256          *
27257          * The example below makes use of this feature:
27258          * ```html
27259          *   <header ng-repeat-start="item in items">
27260          *     Header {{ item }}
27261          *   </header>
27262          *   <div class="body">
27263          *     Body {{ item }}
27264          *   </div>
27265          *   <footer ng-repeat-end>
27266          *     Footer {{ item }}
27267          *   </footer>
27268          * ```
27269          *
27270          * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
27271          * ```html
27272          *   <header>
27273          *     Header A
27274          *   </header>
27275          *   <div class="body">
27276          *     Body A
27277          *   </div>
27278          *   <footer>
27279          *     Footer A
27280          *   </footer>
27281          *   <header>
27282          *     Header B
27283          *   </header>
27284          *   <div class="body">
27285          *     Body B
27286          *   </div>
27287          *   <footer>
27288          *     Footer B
27289          *   </footer>
27290          * ```
27291          *
27292          * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
27293          * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
27294          *
27295          * @animations
27296          * **.enter** - when a new item is added to the list or when an item is revealed after a filter
27297          *
27298          * **.leave** - when an item is removed from the list or when an item is filtered out
27299          *
27300          * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
27301          *
27302          * @element ANY
27303          * @scope
27304          * @priority 1000
27305          * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
27306          *   formats are currently supported:
27307          *
27308          *   * `variable in expression` – where variable is the user defined loop variable and `expression`
27309          *     is a scope expression giving the collection to enumerate.
27310          *
27311          *     For example: `album in artist.albums`.
27312          *
27313          *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
27314          *     and `expression` is the scope expression giving the collection to enumerate.
27315          *
27316          *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
27317          *
27318          *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
27319          *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
27320          *     is specified, ng-repeat associates elements by identity. It is an error to have
27321          *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
27322          *     mapped to the same DOM element, which is not possible.)
27323          *
27324          *     Note that the tracking expression must come last, after any filters, and the alias expression.
27325          *
27326          *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
27327          *     will be associated by item identity in the array.
27328          *
27329          *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
27330          *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
27331          *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
27332          *     element in the same way in the DOM.
27333          *
27334          *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
27335          *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
27336          *     property is same.
27337          *
27338          *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
27339          *     to items in conjunction with a tracking expression.
27340          *
27341          *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
27342          *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
27343          *     when a filter is active on the repeater, but the filtered result set is empty.
27344          *
27345          *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
27346          *     the items have been processed through the filter.
27347          *
27348          *     Please note that `as [variable name] is not an operator but rather a part of ngRepeat micro-syntax so it can be used only at the end
27349          *     (and not as operator, inside an expression).
27350          *
27351          *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
27352          *
27353          * @example
27354          * This example initializes the scope to a list of names and
27355          * then uses `ngRepeat` to display every person:
27356           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27357             <file name="index.html">
27358               <div ng-init="friends = [
27359                 {name:'John', age:25, gender:'boy'},
27360                 {name:'Jessie', age:30, gender:'girl'},
27361                 {name:'Johanna', age:28, gender:'girl'},
27362                 {name:'Joy', age:15, gender:'girl'},
27363                 {name:'Mary', age:28, gender:'girl'},
27364                 {name:'Peter', age:95, gender:'boy'},
27365                 {name:'Sebastian', age:50, gender:'boy'},
27366                 {name:'Erika', age:27, gender:'girl'},
27367                 {name:'Patrick', age:40, gender:'boy'},
27368                 {name:'Samantha', age:60, gender:'girl'}
27369               ]">
27370                 I have {{friends.length}} friends. They are:
27371                 <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
27372                 <ul class="example-animate-container">
27373                   <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
27374                     [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
27375                   </li>
27376                   <li class="animate-repeat" ng-if="results.length == 0">
27377                     <strong>No results found...</strong>
27378                   </li>
27379                 </ul>
27380               </div>
27381             </file>
27382             <file name="animations.css">
27383               .example-animate-container {
27384                 background:white;
27385                 border:1px solid black;
27386                 list-style:none;
27387                 margin:0;
27388                 padding:0 10px;
27389               }
27390
27391               .animate-repeat {
27392                 line-height:40px;
27393                 list-style:none;
27394                 box-sizing:border-box;
27395               }
27396
27397               .animate-repeat.ng-move,
27398               .animate-repeat.ng-enter,
27399               .animate-repeat.ng-leave {
27400                 transition:all linear 0.5s;
27401               }
27402
27403               .animate-repeat.ng-leave.ng-leave-active,
27404               .animate-repeat.ng-move,
27405               .animate-repeat.ng-enter {
27406                 opacity:0;
27407                 max-height:0;
27408               }
27409
27410               .animate-repeat.ng-leave,
27411               .animate-repeat.ng-move.ng-move-active,
27412               .animate-repeat.ng-enter.ng-enter-active {
27413                 opacity:1;
27414                 max-height:40px;
27415               }
27416             </file>
27417             <file name="protractor.js" type="protractor">
27418               var friends = element.all(by.repeater('friend in friends'));
27419
27420               it('should render initial data set', function() {
27421                 expect(friends.count()).toBe(10);
27422                 expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
27423                 expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
27424                 expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
27425                 expect(element(by.binding('friends.length')).getText())
27426                     .toMatch("I have 10 friends. They are:");
27427               });
27428
27429                it('should update repeater when filter predicate changes', function() {
27430                  expect(friends.count()).toBe(10);
27431
27432                  element(by.model('q')).sendKeys('ma');
27433
27434                  expect(friends.count()).toBe(2);
27435                  expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
27436                  expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
27437                });
27438               </file>
27439             </example>
27440          */
27441         var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
27442           var NG_REMOVED = '$$NG_REMOVED';
27443           var ngRepeatMinErr = minErr('ngRepeat');
27444
27445           var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
27446             // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
27447             scope[valueIdentifier] = value;
27448             if (keyIdentifier) scope[keyIdentifier] = key;
27449             scope.$index = index;
27450             scope.$first = (index === 0);
27451             scope.$last = (index === (arrayLength - 1));
27452             scope.$middle = !(scope.$first || scope.$last);
27453             // jshint bitwise: false
27454             scope.$odd = !(scope.$even = (index&1) === 0);
27455             // jshint bitwise: true
27456           };
27457
27458           var getBlockStart = function(block) {
27459             return block.clone[0];
27460           };
27461
27462           var getBlockEnd = function(block) {
27463             return block.clone[block.clone.length - 1];
27464           };
27465
27466
27467           return {
27468             restrict: 'A',
27469             multiElement: true,
27470             transclude: 'element',
27471             priority: 1000,
27472             terminal: true,
27473             $$tlb: true,
27474             compile: function ngRepeatCompile($element, $attr) {
27475               var expression = $attr.ngRepeat;
27476               var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
27477
27478               var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
27479
27480               if (!match) {
27481                 throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
27482                     expression);
27483               }
27484
27485               var lhs = match[1];
27486               var rhs = match[2];
27487               var aliasAs = match[3];
27488               var trackByExp = match[4];
27489
27490               match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
27491
27492               if (!match) {
27493                 throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
27494                     lhs);
27495               }
27496               var valueIdentifier = match[3] || match[1];
27497               var keyIdentifier = match[2];
27498
27499               if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
27500                   /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
27501                 throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
27502                   aliasAs);
27503               }
27504
27505               var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
27506               var hashFnLocals = {$id: hashKey};
27507
27508               if (trackByExp) {
27509                 trackByExpGetter = $parse(trackByExp);
27510               } else {
27511                 trackByIdArrayFn = function(key, value) {
27512                   return hashKey(value);
27513                 };
27514                 trackByIdObjFn = function(key) {
27515                   return key;
27516                 };
27517               }
27518
27519               return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
27520
27521                 if (trackByExpGetter) {
27522                   trackByIdExpFn = function(key, value, index) {
27523                     // assign key, value, and $index to the locals so that they can be used in hash functions
27524                     if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
27525                     hashFnLocals[valueIdentifier] = value;
27526                     hashFnLocals.$index = index;
27527                     return trackByExpGetter($scope, hashFnLocals);
27528                   };
27529                 }
27530
27531                 // Store a list of elements from previous run. This is a hash where key is the item from the
27532                 // iterator, and the value is objects with following properties.
27533                 //   - scope: bound scope
27534                 //   - element: previous element.
27535                 //   - index: position
27536                 //
27537                 // We are using no-proto object so that we don't need to guard against inherited props via
27538                 // hasOwnProperty.
27539                 var lastBlockMap = createMap();
27540
27541                 //watch props
27542                 $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
27543                   var index, length,
27544                       previousNode = $element[0],     // node that cloned nodes should be inserted after
27545                                                       // initialized to the comment node anchor
27546                       nextNode,
27547                       // Same as lastBlockMap but it has the current state. It will become the
27548                       // lastBlockMap on the next iteration.
27549                       nextBlockMap = createMap(),
27550                       collectionLength,
27551                       key, value, // key/value of iteration
27552                       trackById,
27553                       trackByIdFn,
27554                       collectionKeys,
27555                       block,       // last object information {scope, element, id}
27556                       nextBlockOrder,
27557                       elementsToRemove;
27558
27559                   if (aliasAs) {
27560                     $scope[aliasAs] = collection;
27561                   }
27562
27563                   if (isArrayLike(collection)) {
27564                     collectionKeys = collection;
27565                     trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
27566                   } else {
27567                     trackByIdFn = trackByIdExpFn || trackByIdObjFn;
27568                     // if object, extract keys, in enumeration order, unsorted
27569                     collectionKeys = [];
27570                     for (var itemKey in collection) {
27571                       if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
27572                         collectionKeys.push(itemKey);
27573                       }
27574                     }
27575                   }
27576
27577                   collectionLength = collectionKeys.length;
27578                   nextBlockOrder = new Array(collectionLength);
27579
27580                   // locate existing items
27581                   for (index = 0; index < collectionLength; index++) {
27582                     key = (collection === collectionKeys) ? index : collectionKeys[index];
27583                     value = collection[key];
27584                     trackById = trackByIdFn(key, value, index);
27585                     if (lastBlockMap[trackById]) {
27586                       // found previously seen block
27587                       block = lastBlockMap[trackById];
27588                       delete lastBlockMap[trackById];
27589                       nextBlockMap[trackById] = block;
27590                       nextBlockOrder[index] = block;
27591                     } else if (nextBlockMap[trackById]) {
27592                       // if collision detected. restore lastBlockMap and throw an error
27593                       forEach(nextBlockOrder, function(block) {
27594                         if (block && block.scope) lastBlockMap[block.id] = block;
27595                       });
27596                       throw ngRepeatMinErr('dupes',
27597                           "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
27598                           expression, trackById, value);
27599                     } else {
27600                       // new never before seen block
27601                       nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
27602                       nextBlockMap[trackById] = true;
27603                     }
27604                   }
27605
27606                   // remove leftover items
27607                   for (var blockKey in lastBlockMap) {
27608                     block = lastBlockMap[blockKey];
27609                     elementsToRemove = getBlockNodes(block.clone);
27610                     $animate.leave(elementsToRemove);
27611                     if (elementsToRemove[0].parentNode) {
27612                       // if the element was not removed yet because of pending animation, mark it as deleted
27613                       // so that we can ignore it later
27614                       for (index = 0, length = elementsToRemove.length; index < length; index++) {
27615                         elementsToRemove[index][NG_REMOVED] = true;
27616                       }
27617                     }
27618                     block.scope.$destroy();
27619                   }
27620
27621                   // we are not using forEach for perf reasons (trying to avoid #call)
27622                   for (index = 0; index < collectionLength; index++) {
27623                     key = (collection === collectionKeys) ? index : collectionKeys[index];
27624                     value = collection[key];
27625                     block = nextBlockOrder[index];
27626
27627                     if (block.scope) {
27628                       // if we have already seen this object, then we need to reuse the
27629                       // associated scope/element
27630
27631                       nextNode = previousNode;
27632
27633                       // skip nodes that are already pending removal via leave animation
27634                       do {
27635                         nextNode = nextNode.nextSibling;
27636                       } while (nextNode && nextNode[NG_REMOVED]);
27637
27638                       if (getBlockStart(block) != nextNode) {
27639                         // existing item which got moved
27640                         $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
27641                       }
27642                       previousNode = getBlockEnd(block);
27643                       updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
27644                     } else {
27645                       // new item which we don't know about
27646                       $transclude(function ngRepeatTransclude(clone, scope) {
27647                         block.scope = scope;
27648                         // http://jsperf.com/clone-vs-createcomment
27649                         var endNode = ngRepeatEndComment.cloneNode(false);
27650                         clone[clone.length++] = endNode;
27651
27652                         // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
27653                         $animate.enter(clone, null, jqLite(previousNode));
27654                         previousNode = endNode;
27655                         // Note: We only need the first/last node of the cloned nodes.
27656                         // However, we need to keep the reference to the jqlite wrapper as it might be changed later
27657                         // by a directive with templateUrl when its template arrives.
27658                         block.clone = clone;
27659                         nextBlockMap[block.id] = block;
27660                         updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
27661                       });
27662                     }
27663                   }
27664                   lastBlockMap = nextBlockMap;
27665                 });
27666               };
27667             }
27668           };
27669         }];
27670
27671         var NG_HIDE_CLASS = 'ng-hide';
27672         var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
27673         /**
27674          * @ngdoc directive
27675          * @name ngShow
27676          * @multiElement
27677          *
27678          * @description
27679          * The `ngShow` directive shows or hides the given HTML element based on the expression
27680          * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
27681          * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27682          * in AngularJS and sets the display style to none (using an !important flag).
27683          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27684          *
27685          * ```html
27686          * <!-- when $scope.myValue is truthy (element is visible) -->
27687          * <div ng-show="myValue"></div>
27688          *
27689          * <!-- when $scope.myValue is falsy (element is hidden) -->
27690          * <div ng-show="myValue" class="ng-hide"></div>
27691          * ```
27692          *
27693          * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
27694          * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
27695          * from the element causing the element not to appear hidden.
27696          *
27697          * ## Why is !important used?
27698          *
27699          * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27700          * can be easily overridden by heavier selectors. For example, something as simple
27701          * as changing the display style on a HTML list item would make hidden elements appear visible.
27702          * This also becomes a bigger issue when dealing with CSS frameworks.
27703          *
27704          * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27705          * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27706          * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27707          *
27708          * ### Overriding `.ng-hide`
27709          *
27710          * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27711          * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27712          * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
27713          * with extra animation classes that can be added.
27714          *
27715          * ```css
27716          * .ng-hide:not(.ng-hide-animate) {
27717          *   /&#42; this is just another form of hiding an element &#42;/
27718          *   display: block!important;
27719          *   position: absolute;
27720          *   top: -9999px;
27721          *   left: -9999px;
27722          * }
27723          * ```
27724          *
27725          * By default you don't need to override in CSS anything and the animations will work around the display style.
27726          *
27727          * ## A note about animations with `ngShow`
27728          *
27729          * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27730          * is true and false. This system works like the animation system present with ngClass except that
27731          * you must also include the !important flag to override the display property
27732          * so that you can perform an animation when the element is hidden during the time of the animation.
27733          *
27734          * ```css
27735          * //
27736          * //a working example can be found at the bottom of this page
27737          * //
27738          * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27739          *   /&#42; this is required as of 1.3x to properly
27740          *      apply all styling in a show/hide animation &#42;/
27741          *   transition: 0s linear all;
27742          * }
27743          *
27744          * .my-element.ng-hide-add-active,
27745          * .my-element.ng-hide-remove-active {
27746          *   /&#42; the transition is defined in the active class &#42;/
27747          *   transition: 1s linear all;
27748          * }
27749          *
27750          * .my-element.ng-hide-add { ... }
27751          * .my-element.ng-hide-add.ng-hide-add-active { ... }
27752          * .my-element.ng-hide-remove { ... }
27753          * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27754          * ```
27755          *
27756          * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27757          * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27758          *
27759          * @animations
27760          * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
27761          * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
27762          *
27763          * @element ANY
27764          * @param {expression} ngShow If the {@link guide/expression expression} is truthy
27765          *     then the element is shown or hidden respectively.
27766          *
27767          * @example
27768           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27769             <file name="index.html">
27770               Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
27771               <div>
27772                 Show:
27773                 <div class="check-element animate-show" ng-show="checked">
27774                   <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27775                 </div>
27776               </div>
27777               <div>
27778                 Hide:
27779                 <div class="check-element animate-show" ng-hide="checked">
27780                   <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27781                 </div>
27782               </div>
27783             </file>
27784             <file name="glyphicons.css">
27785               @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27786             </file>
27787             <file name="animations.css">
27788               .animate-show {
27789                 line-height: 20px;
27790                 opacity: 1;
27791                 padding: 10px;
27792                 border: 1px solid black;
27793                 background: white;
27794               }
27795
27796               .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
27797                 transition: all linear 0.5s;
27798               }
27799
27800               .animate-show.ng-hide {
27801                 line-height: 0;
27802                 opacity: 0;
27803                 padding: 0 10px;
27804               }
27805
27806               .check-element {
27807                 padding: 10px;
27808                 border: 1px solid black;
27809                 background: white;
27810               }
27811             </file>
27812             <file name="protractor.js" type="protractor">
27813               var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27814               var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27815
27816               it('should check ng-show / ng-hide', function() {
27817                 expect(thumbsUp.isDisplayed()).toBeFalsy();
27818                 expect(thumbsDown.isDisplayed()).toBeTruthy();
27819
27820                 element(by.model('checked')).click();
27821
27822                 expect(thumbsUp.isDisplayed()).toBeTruthy();
27823                 expect(thumbsDown.isDisplayed()).toBeFalsy();
27824               });
27825             </file>
27826           </example>
27827          */
27828         var ngShowDirective = ['$animate', function($animate) {
27829           return {
27830             restrict: 'A',
27831             multiElement: true,
27832             link: function(scope, element, attr) {
27833               scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
27834                 // we're adding a temporary, animation-specific class for ng-hide since this way
27835                 // we can control when the element is actually displayed on screen without having
27836                 // to have a global/greedy CSS selector that breaks when other animations are run.
27837                 // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
27838                 $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
27839                   tempClasses: NG_HIDE_IN_PROGRESS_CLASS
27840                 });
27841               });
27842             }
27843           };
27844         }];
27845
27846
27847         /**
27848          * @ngdoc directive
27849          * @name ngHide
27850          * @multiElement
27851          *
27852          * @description
27853          * The `ngHide` directive shows or hides the given HTML element based on the expression
27854          * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
27855          * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27856          * in AngularJS and sets the display style to none (using an !important flag).
27857          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27858          *
27859          * ```html
27860          * <!-- when $scope.myValue is truthy (element is hidden) -->
27861          * <div ng-hide="myValue" class="ng-hide"></div>
27862          *
27863          * <!-- when $scope.myValue is falsy (element is visible) -->
27864          * <div ng-hide="myValue"></div>
27865          * ```
27866          *
27867          * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
27868          * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
27869          * from the element causing the element not to appear hidden.
27870          *
27871          * ## Why is !important used?
27872          *
27873          * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27874          * can be easily overridden by heavier selectors. For example, something as simple
27875          * as changing the display style on a HTML list item would make hidden elements appear visible.
27876          * This also becomes a bigger issue when dealing with CSS frameworks.
27877          *
27878          * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27879          * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27880          * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27881          *
27882          * ### Overriding `.ng-hide`
27883          *
27884          * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27885          * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27886          * class in CSS:
27887          *
27888          * ```css
27889          * .ng-hide {
27890          *   /&#42; this is just another form of hiding an element &#42;/
27891          *   display: block!important;
27892          *   position: absolute;
27893          *   top: -9999px;
27894          *   left: -9999px;
27895          * }
27896          * ```
27897          *
27898          * By default you don't need to override in CSS anything and the animations will work around the display style.
27899          *
27900          * ## A note about animations with `ngHide`
27901          *
27902          * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27903          * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
27904          * CSS class is added and removed for you instead of your own CSS class.
27905          *
27906          * ```css
27907          * //
27908          * //a working example can be found at the bottom of this page
27909          * //
27910          * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27911          *   transition: 0.5s linear all;
27912          * }
27913          *
27914          * .my-element.ng-hide-add { ... }
27915          * .my-element.ng-hide-add.ng-hide-add-active { ... }
27916          * .my-element.ng-hide-remove { ... }
27917          * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27918          * ```
27919          *
27920          * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27921          * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27922          *
27923          * @animations
27924          * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
27925          * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
27926          *
27927          * @element ANY
27928          * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
27929          *     the element is shown or hidden respectively.
27930          *
27931          * @example
27932           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27933             <file name="index.html">
27934               Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
27935               <div>
27936                 Show:
27937                 <div class="check-element animate-hide" ng-show="checked">
27938                   <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27939                 </div>
27940               </div>
27941               <div>
27942                 Hide:
27943                 <div class="check-element animate-hide" ng-hide="checked">
27944                   <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27945                 </div>
27946               </div>
27947             </file>
27948             <file name="glyphicons.css">
27949               @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27950             </file>
27951             <file name="animations.css">
27952               .animate-hide {
27953                 transition: all linear 0.5s;
27954                 line-height: 20px;
27955                 opacity: 1;
27956                 padding: 10px;
27957                 border: 1px solid black;
27958                 background: white;
27959               }
27960
27961               .animate-hide.ng-hide {
27962                 line-height: 0;
27963                 opacity: 0;
27964                 padding: 0 10px;
27965               }
27966
27967               .check-element {
27968                 padding: 10px;
27969                 border: 1px solid black;
27970                 background: white;
27971               }
27972             </file>
27973             <file name="protractor.js" type="protractor">
27974               var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27975               var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27976
27977               it('should check ng-show / ng-hide', function() {
27978                 expect(thumbsUp.isDisplayed()).toBeFalsy();
27979                 expect(thumbsDown.isDisplayed()).toBeTruthy();
27980
27981                 element(by.model('checked')).click();
27982
27983                 expect(thumbsUp.isDisplayed()).toBeTruthy();
27984                 expect(thumbsDown.isDisplayed()).toBeFalsy();
27985               });
27986             </file>
27987           </example>
27988          */
27989         var ngHideDirective = ['$animate', function($animate) {
27990           return {
27991             restrict: 'A',
27992             multiElement: true,
27993             link: function(scope, element, attr) {
27994               scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
27995                 // The comment inside of the ngShowDirective explains why we add and
27996                 // remove a temporary class for the show/hide animation
27997                 $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
27998                   tempClasses: NG_HIDE_IN_PROGRESS_CLASS
27999                 });
28000               });
28001             }
28002           };
28003         }];
28004
28005         /**
28006          * @ngdoc directive
28007          * @name ngStyle
28008          * @restrict AC
28009          *
28010          * @description
28011          * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
28012          *
28013          * @element ANY
28014          * @param {expression} ngStyle
28015          *
28016          * {@link guide/expression Expression} which evals to an
28017          * object whose keys are CSS style names and values are corresponding values for those CSS
28018          * keys.
28019          *
28020          * Since some CSS style names are not valid keys for an object, they must be quoted.
28021          * See the 'background-color' style in the example below.
28022          *
28023          * @example
28024            <example>
28025              <file name="index.html">
28026                 <input type="button" value="set color" ng-click="myStyle={color:'red'}">
28027                 <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
28028                 <input type="button" value="clear" ng-click="myStyle={}">
28029                 <br/>
28030                 <span ng-style="myStyle">Sample Text</span>
28031                 <pre>myStyle={{myStyle}}</pre>
28032              </file>
28033              <file name="style.css">
28034                span {
28035                  color: black;
28036                }
28037              </file>
28038              <file name="protractor.js" type="protractor">
28039                var colorSpan = element(by.css('span'));
28040
28041                it('should check ng-style', function() {
28042                  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
28043                  element(by.css('input[value=\'set color\']')).click();
28044                  expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
28045                  element(by.css('input[value=clear]')).click();
28046                  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
28047                });
28048              </file>
28049            </example>
28050          */
28051         var ngStyleDirective = ngDirective(function(scope, element, attr) {
28052           scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
28053             if (oldStyles && (newStyles !== oldStyles)) {
28054               forEach(oldStyles, function(val, style) { element.css(style, '');});
28055             }
28056             if (newStyles) element.css(newStyles);
28057           }, true);
28058         });
28059
28060         /**
28061          * @ngdoc directive
28062          * @name ngSwitch
28063          * @restrict EA
28064          *
28065          * @description
28066          * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
28067          * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
28068          * as specified in the template.
28069          *
28070          * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
28071          * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
28072          * matches the value obtained from the evaluated expression. In other words, you define a container element
28073          * (where you place the directive), place an expression on the **`on="..."` attribute**
28074          * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
28075          * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
28076          * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
28077          * attribute is displayed.
28078          *
28079          * <div class="alert alert-info">
28080          * Be aware that the attribute values to match against cannot be expressions. They are interpreted
28081          * as literal string values to match against.
28082          * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
28083          * value of the expression `$scope.someVal`.
28084          * </div>
28085
28086          * @animations
28087          * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
28088          * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
28089          *
28090          * @usage
28091          *
28092          * ```
28093          * <ANY ng-switch="expression">
28094          *   <ANY ng-switch-when="matchValue1">...</ANY>
28095          *   <ANY ng-switch-when="matchValue2">...</ANY>
28096          *   <ANY ng-switch-default>...</ANY>
28097          * </ANY>
28098          * ```
28099          *
28100          *
28101          * @scope
28102          * @priority 1200
28103          * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
28104          * On child elements add:
28105          *
28106          * * `ngSwitchWhen`: the case statement to match against. If match then this
28107          *   case will be displayed. If the same match appears multiple times, all the
28108          *   elements will be displayed.
28109          * * `ngSwitchDefault`: the default case when no other case match. If there
28110          *   are multiple default cases, all of them will be displayed when no other
28111          *   case match.
28112          *
28113          *
28114          * @example
28115           <example module="switchExample" deps="angular-animate.js" animations="true">
28116             <file name="index.html">
28117               <div ng-controller="ExampleController">
28118                 <select ng-model="selection" ng-options="item for item in items">
28119                 </select>
28120                 <code>selection={{selection}}</code>
28121                 <hr/>
28122                 <div class="animate-switch-container"
28123                   ng-switch on="selection">
28124                     <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
28125                     <div class="animate-switch" ng-switch-when="home">Home Span</div>
28126                     <div class="animate-switch" ng-switch-default>default</div>
28127                 </div>
28128               </div>
28129             </file>
28130             <file name="script.js">
28131               angular.module('switchExample', ['ngAnimate'])
28132                 .controller('ExampleController', ['$scope', function($scope) {
28133                   $scope.items = ['settings', 'home', 'other'];
28134                   $scope.selection = $scope.items[0];
28135                 }]);
28136             </file>
28137             <file name="animations.css">
28138               .animate-switch-container {
28139                 position:relative;
28140                 background:white;
28141                 border:1px solid black;
28142                 height:40px;
28143                 overflow:hidden;
28144               }
28145
28146               .animate-switch {
28147                 padding:10px;
28148               }
28149
28150               .animate-switch.ng-animate {
28151                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
28152
28153                 position:absolute;
28154                 top:0;
28155                 left:0;
28156                 right:0;
28157                 bottom:0;
28158               }
28159
28160               .animate-switch.ng-leave.ng-leave-active,
28161               .animate-switch.ng-enter {
28162                 top:-50px;
28163               }
28164               .animate-switch.ng-leave,
28165               .animate-switch.ng-enter.ng-enter-active {
28166                 top:0;
28167               }
28168             </file>
28169             <file name="protractor.js" type="protractor">
28170               var switchElem = element(by.css('[ng-switch]'));
28171               var select = element(by.model('selection'));
28172
28173               it('should start in settings', function() {
28174                 expect(switchElem.getText()).toMatch(/Settings Div/);
28175               });
28176               it('should change to home', function() {
28177                 select.all(by.css('option')).get(1).click();
28178                 expect(switchElem.getText()).toMatch(/Home Span/);
28179               });
28180               it('should select default', function() {
28181                 select.all(by.css('option')).get(2).click();
28182                 expect(switchElem.getText()).toMatch(/default/);
28183               });
28184             </file>
28185           </example>
28186          */
28187         var ngSwitchDirective = ['$animate', function($animate) {
28188           return {
28189             require: 'ngSwitch',
28190
28191             // asks for $scope to fool the BC controller module
28192             controller: ['$scope', function ngSwitchController() {
28193              this.cases = {};
28194             }],
28195             link: function(scope, element, attr, ngSwitchController) {
28196               var watchExpr = attr.ngSwitch || attr.on,
28197                   selectedTranscludes = [],
28198                   selectedElements = [],
28199                   previousLeaveAnimations = [],
28200                   selectedScopes = [];
28201
28202               var spliceFactory = function(array, index) {
28203                   return function() { array.splice(index, 1); };
28204               };
28205
28206               scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
28207                 var i, ii;
28208                 for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
28209                   $animate.cancel(previousLeaveAnimations[i]);
28210                 }
28211                 previousLeaveAnimations.length = 0;
28212
28213                 for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
28214                   var selected = getBlockNodes(selectedElements[i].clone);
28215                   selectedScopes[i].$destroy();
28216                   var promise = previousLeaveAnimations[i] = $animate.leave(selected);
28217                   promise.then(spliceFactory(previousLeaveAnimations, i));
28218                 }
28219
28220                 selectedElements.length = 0;
28221                 selectedScopes.length = 0;
28222
28223                 if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
28224                   forEach(selectedTranscludes, function(selectedTransclude) {
28225                     selectedTransclude.transclude(function(caseElement, selectedScope) {
28226                       selectedScopes.push(selectedScope);
28227                       var anchor = selectedTransclude.element;
28228                       caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
28229                       var block = { clone: caseElement };
28230
28231                       selectedElements.push(block);
28232                       $animate.enter(caseElement, anchor.parent(), anchor);
28233                     });
28234                   });
28235                 }
28236               });
28237             }
28238           };
28239         }];
28240
28241         var ngSwitchWhenDirective = ngDirective({
28242           transclude: 'element',
28243           priority: 1200,
28244           require: '^ngSwitch',
28245           multiElement: true,
28246           link: function(scope, element, attrs, ctrl, $transclude) {
28247             ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
28248             ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
28249           }
28250         });
28251
28252         var ngSwitchDefaultDirective = ngDirective({
28253           transclude: 'element',
28254           priority: 1200,
28255           require: '^ngSwitch',
28256           multiElement: true,
28257           link: function(scope, element, attr, ctrl, $transclude) {
28258             ctrl.cases['?'] = (ctrl.cases['?'] || []);
28259             ctrl.cases['?'].push({ transclude: $transclude, element: element });
28260            }
28261         });
28262
28263         /**
28264          * @ngdoc directive
28265          * @name ngTransclude
28266          * @restrict EAC
28267          *
28268          * @description
28269          * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
28270          *
28271          * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
28272          *
28273          * @element ANY
28274          *
28275          * @example
28276            <example module="transcludeExample">
28277              <file name="index.html">
28278                <script>
28279                  angular.module('transcludeExample', [])
28280                   .directive('pane', function(){
28281                      return {
28282                        restrict: 'E',
28283                        transclude: true,
28284                        scope: { title:'@' },
28285                        template: '<div style="border: 1px solid black;">' +
28286                                    '<div style="background-color: gray">{{title}}</div>' +
28287                                    '<ng-transclude></ng-transclude>' +
28288                                  '</div>'
28289                      };
28290                  })
28291                  .controller('ExampleController', ['$scope', function($scope) {
28292                    $scope.title = 'Lorem Ipsum';
28293                    $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
28294                  }]);
28295                </script>
28296                <div ng-controller="ExampleController">
28297                  <input ng-model="title" aria-label="title"> <br/>
28298                  <textarea ng-model="text" aria-label="text"></textarea> <br/>
28299                  <pane title="{{title}}">{{text}}</pane>
28300                </div>
28301              </file>
28302              <file name="protractor.js" type="protractor">
28303                 it('should have transcluded', function() {
28304                   var titleElement = element(by.model('title'));
28305                   titleElement.clear();
28306                   titleElement.sendKeys('TITLE');
28307                   var textElement = element(by.model('text'));
28308                   textElement.clear();
28309                   textElement.sendKeys('TEXT');
28310                   expect(element(by.binding('title')).getText()).toEqual('TITLE');
28311                   expect(element(by.binding('text')).getText()).toEqual('TEXT');
28312                 });
28313              </file>
28314            </example>
28315          *
28316          */
28317         var ngTranscludeDirective = ngDirective({
28318           restrict: 'EAC',
28319           link: function($scope, $element, $attrs, controller, $transclude) {
28320             if (!$transclude) {
28321               throw minErr('ngTransclude')('orphan',
28322                'Illegal use of ngTransclude directive in the template! ' +
28323                'No parent directive that requires a transclusion found. ' +
28324                'Element: {0}',
28325                startingTag($element));
28326             }
28327
28328             $transclude(function(clone) {
28329               $element.empty();
28330               $element.append(clone);
28331             });
28332           }
28333         });
28334
28335         /**
28336          * @ngdoc directive
28337          * @name script
28338          * @restrict E
28339          *
28340          * @description
28341          * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
28342          * template can be used by {@link ng.directive:ngInclude `ngInclude`},
28343          * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
28344          * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
28345          * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
28346          *
28347          * @param {string} type Must be set to `'text/ng-template'`.
28348          * @param {string} id Cache name of the template.
28349          *
28350          * @example
28351           <example>
28352             <file name="index.html">
28353               <script type="text/ng-template" id="/tpl.html">
28354                 Content of the template.
28355               </script>
28356
28357               <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
28358               <div id="tpl-content" ng-include src="currentTpl"></div>
28359             </file>
28360             <file name="protractor.js" type="protractor">
28361               it('should load template defined inside script tag', function() {
28362                 element(by.css('#tpl-link')).click();
28363                 expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
28364               });
28365             </file>
28366           </example>
28367          */
28368         var scriptDirective = ['$templateCache', function($templateCache) {
28369           return {
28370             restrict: 'E',
28371             terminal: true,
28372             compile: function(element, attr) {
28373               if (attr.type == 'text/ng-template') {
28374                 var templateUrl = attr.id,
28375                     text = element[0].text;
28376
28377                 $templateCache.put(templateUrl, text);
28378               }
28379             }
28380           };
28381         }];
28382
28383         var noopNgModelController = { $setViewValue: noop, $render: noop };
28384
28385         function chromeHack(optionElement) {
28386           // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
28387           // Adding an <option selected="selected"> element to a <select required="required"> should
28388           // automatically select the new element
28389           if (optionElement[0].hasAttribute('selected')) {
28390             optionElement[0].selected = true;
28391           }
28392         }
28393
28394         /**
28395          * @ngdoc type
28396          * @name  select.SelectController
28397          * @description
28398          * The controller for the `<select>` directive. This provides support for reading
28399          * and writing the selected value(s) of the control and also coordinates dynamically
28400          * added `<option>` elements, perhaps by an `ngRepeat` directive.
28401          */
28402         var SelectController =
28403                 ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
28404
28405           var self = this,
28406               optionsMap = new HashMap();
28407
28408           // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
28409           self.ngModelCtrl = noopNgModelController;
28410
28411           // The "unknown" option is one that is prepended to the list if the viewValue
28412           // does not match any of the options. When it is rendered the value of the unknown
28413           // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
28414           //
28415           // We can't just jqLite('<option>') since jqLite is not smart enough
28416           // to create it in <select> and IE barfs otherwise.
28417           self.unknownOption = jqLite(document.createElement('option'));
28418           self.renderUnknownOption = function(val) {
28419             var unknownVal = '? ' + hashKey(val) + ' ?';
28420             self.unknownOption.val(unknownVal);
28421             $element.prepend(self.unknownOption);
28422             $element.val(unknownVal);
28423           };
28424
28425           $scope.$on('$destroy', function() {
28426             // disable unknown option so that we don't do work when the whole select is being destroyed
28427             self.renderUnknownOption = noop;
28428           });
28429
28430           self.removeUnknownOption = function() {
28431             if (self.unknownOption.parent()) self.unknownOption.remove();
28432           };
28433
28434
28435           // Read the value of the select control, the implementation of this changes depending
28436           // upon whether the select can have multiple values and whether ngOptions is at work.
28437           self.readValue = function readSingleValue() {
28438             self.removeUnknownOption();
28439             return $element.val();
28440           };
28441
28442
28443           // Write the value to the select control, the implementation of this changes depending
28444           // upon whether the select can have multiple values and whether ngOptions is at work.
28445           self.writeValue = function writeSingleValue(value) {
28446             if (self.hasOption(value)) {
28447               self.removeUnknownOption();
28448               $element.val(value);
28449               if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
28450             } else {
28451               if (value == null && self.emptyOption) {
28452                 self.removeUnknownOption();
28453                 $element.val('');
28454               } else {
28455                 self.renderUnknownOption(value);
28456               }
28457             }
28458           };
28459
28460
28461           // Tell the select control that an option, with the given value, has been added
28462           self.addOption = function(value, element) {
28463             assertNotHasOwnProperty(value, '"option value"');
28464             if (value === '') {
28465               self.emptyOption = element;
28466             }
28467             var count = optionsMap.get(value) || 0;
28468             optionsMap.put(value, count + 1);
28469             self.ngModelCtrl.$render();
28470             chromeHack(element);
28471           };
28472
28473           // Tell the select control that an option, with the given value, has been removed
28474           self.removeOption = function(value) {
28475             var count = optionsMap.get(value);
28476             if (count) {
28477               if (count === 1) {
28478                 optionsMap.remove(value);
28479                 if (value === '') {
28480                   self.emptyOption = undefined;
28481                 }
28482               } else {
28483                 optionsMap.put(value, count - 1);
28484               }
28485             }
28486           };
28487
28488           // Check whether the select control has an option matching the given value
28489           self.hasOption = function(value) {
28490             return !!optionsMap.get(value);
28491           };
28492
28493
28494           self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
28495
28496             if (interpolateValueFn) {
28497               // The value attribute is interpolated
28498               var oldVal;
28499               optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
28500                 if (isDefined(oldVal)) {
28501                   self.removeOption(oldVal);
28502                 }
28503                 oldVal = newVal;
28504                 self.addOption(newVal, optionElement);
28505               });
28506             } else if (interpolateTextFn) {
28507               // The text content is interpolated
28508               optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
28509                 optionAttrs.$set('value', newVal);
28510                 if (oldVal !== newVal) {
28511                   self.removeOption(oldVal);
28512                 }
28513                 self.addOption(newVal, optionElement);
28514               });
28515             } else {
28516               // The value attribute is static
28517               self.addOption(optionAttrs.value, optionElement);
28518             }
28519
28520             optionElement.on('$destroy', function() {
28521               self.removeOption(optionAttrs.value);
28522               self.ngModelCtrl.$render();
28523             });
28524           };
28525         }];
28526
28527         /**
28528          * @ngdoc directive
28529          * @name select
28530          * @restrict E
28531          *
28532          * @description
28533          * HTML `SELECT` element with angular data-binding.
28534          *
28535          * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
28536          * between the scope and the `<select>` control (including setting default values).
28537          * Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
28538          * {@link ngOptions `ngOptions`} directives.
28539          *
28540          * When an item in the `<select>` menu is selected, the value of the selected option will be bound
28541          * to the model identified by the `ngModel` directive. With static or repeated options, this is
28542          * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
28543          * If you want dynamic value attributes, you can use interpolation inside the value attribute.
28544          *
28545          * <div class="alert alert-warning">
28546          * Note that the value of a `select` directive used without `ngOptions` is always a string.
28547          * When the model needs to be bound to a non-string value, you must either explictly convert it
28548          * using a directive (see example below) or use `ngOptions` to specify the set of options.
28549          * This is because an option element can only be bound to string values at present.
28550          * </div>
28551          *
28552          * If the viewValue of `ngModel` does not match any of the options, then the control
28553          * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
28554          *
28555          * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
28556          * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
28557          * option. See example below for demonstration.
28558          *
28559          * <div class="alert alert-info">
28560          * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
28561          * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
28562          * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
28563          * comprehension expression, and additionally in reducing memory and increasing speed by not creating
28564          * a new scope for each repeated instance.
28565          * </div>
28566          *
28567          *
28568          * @param {string} ngModel Assignable angular expression to data-bind to.
28569          * @param {string=} name Property name of the form under which the control is published.
28570          * @param {string=} multiple Allows multiple options to be selected. The selected values will be
28571          *     bound to the model as an array.
28572          * @param {string=} required Sets `required` validation error key if the value is not entered.
28573          * @param {string=} ngRequired Adds required attribute and required validation constraint to
28574          * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
28575          * when you want to data-bind to the required attribute.
28576          * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
28577          *    interaction with the select element.
28578          * @param {string=} ngOptions sets the options that the select is populated with and defines what is
28579          * set on the model on selection. See {@link ngOptions `ngOptions`}.
28580          *
28581          * @example
28582          * ### Simple `select` elements with static options
28583          *
28584          * <example name="static-select" module="staticSelect">
28585          * <file name="index.html">
28586          * <div ng-controller="ExampleController">
28587          *   <form name="myForm">
28588          *     <label for="singleSelect"> Single select: </label><br>
28589          *     <select name="singleSelect" ng-model="data.singleSelect">
28590          *       <option value="option-1">Option 1</option>
28591          *       <option value="option-2">Option 2</option>
28592          *     </select><br>
28593          *
28594          *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
28595          *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
28596          *       <option value="">---Please select---</option> <!-- not selected / blank option -->
28597          *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
28598          *       <option value="option-2">Option 2</option>
28599          *     </select><br>
28600          *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
28601          *     <tt>singleSelect = {{data.singleSelect}}</tt>
28602          *
28603          *     <hr>
28604          *     <label for="multipleSelect"> Multiple select: </label><br>
28605          *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
28606          *       <option value="option-1">Option 1</option>
28607          *       <option value="option-2">Option 2</option>
28608          *       <option value="option-3">Option 3</option>
28609          *     </select><br>
28610          *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
28611          *   </form>
28612          * </div>
28613          * </file>
28614          * <file name="app.js">
28615          *  angular.module('staticSelect', [])
28616          *    .controller('ExampleController', ['$scope', function($scope) {
28617          *      $scope.data = {
28618          *       singleSelect: null,
28619          *       multipleSelect: [],
28620          *       option1: 'option-1',
28621          *      };
28622          *
28623          *      $scope.forceUnknownOption = function() {
28624          *        $scope.data.singleSelect = 'nonsense';
28625          *      };
28626          *   }]);
28627          * </file>
28628          *</example>
28629          *
28630          * ### Using `ngRepeat` to generate `select` options
28631          * <example name="ngrepeat-select" module="ngrepeatSelect">
28632          * <file name="index.html">
28633          * <div ng-controller="ExampleController">
28634          *   <form name="myForm">
28635          *     <label for="repeatSelect"> Repeat select: </label>
28636          *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
28637          *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
28638          *     </select>
28639          *   </form>
28640          *   <hr>
28641          *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
28642          * </div>
28643          * </file>
28644          * <file name="app.js">
28645          *  angular.module('ngrepeatSelect', [])
28646          *    .controller('ExampleController', ['$scope', function($scope) {
28647          *      $scope.data = {
28648          *       repeatSelect: null,
28649          *       availableOptions: [
28650          *         {id: '1', name: 'Option A'},
28651          *         {id: '2', name: 'Option B'},
28652          *         {id: '3', name: 'Option C'}
28653          *       ],
28654          *      };
28655          *   }]);
28656          * </file>
28657          *</example>
28658          *
28659          *
28660          * ### Using `select` with `ngOptions` and setting a default value
28661          * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
28662          *
28663          * <example name="select-with-default-values" module="defaultValueSelect">
28664          * <file name="index.html">
28665          * <div ng-controller="ExampleController">
28666          *   <form name="myForm">
28667          *     <label for="mySelect">Make a choice:</label>
28668          *     <select name="mySelect" id="mySelect"
28669          *       ng-options="option.name for option in data.availableOptions track by option.id"
28670          *       ng-model="data.selectedOption"></select>
28671          *   </form>
28672          *   <hr>
28673          *   <tt>option = {{data.selectedOption}}</tt><br/>
28674          * </div>
28675          * </file>
28676          * <file name="app.js">
28677          *  angular.module('defaultValueSelect', [])
28678          *    .controller('ExampleController', ['$scope', function($scope) {
28679          *      $scope.data = {
28680          *       availableOptions: [
28681          *         {id: '1', name: 'Option A'},
28682          *         {id: '2', name: 'Option B'},
28683          *         {id: '3', name: 'Option C'}
28684          *       ],
28685          *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
28686          *       };
28687          *   }]);
28688          * </file>
28689          *</example>
28690          *
28691          *
28692          * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
28693          *
28694          * <example name="select-with-non-string-options" module="nonStringSelect">
28695          *   <file name="index.html">
28696          *     <select ng-model="model.id" convert-to-number>
28697          *       <option value="0">Zero</option>
28698          *       <option value="1">One</option>
28699          *       <option value="2">Two</option>
28700          *     </select>
28701          *     {{ model }}
28702          *   </file>
28703          *   <file name="app.js">
28704          *     angular.module('nonStringSelect', [])
28705          *       .run(function($rootScope) {
28706          *         $rootScope.model = { id: 2 };
28707          *       })
28708          *       .directive('convertToNumber', function() {
28709          *         return {
28710          *           require: 'ngModel',
28711          *           link: function(scope, element, attrs, ngModel) {
28712          *             ngModel.$parsers.push(function(val) {
28713          *               return parseInt(val, 10);
28714          *             });
28715          *             ngModel.$formatters.push(function(val) {
28716          *               return '' + val;
28717          *             });
28718          *           }
28719          *         };
28720          *       });
28721          *   </file>
28722          *   <file name="protractor.js" type="protractor">
28723          *     it('should initialize to model', function() {
28724          *       var select = element(by.css('select'));
28725          *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
28726          *     });
28727          *   </file>
28728          * </example>
28729          *
28730          */
28731         var selectDirective = function() {
28732
28733           return {
28734             restrict: 'E',
28735             require: ['select', '?ngModel'],
28736             controller: SelectController,
28737             priority: 1,
28738             link: {
28739               pre: selectPreLink
28740             }
28741           };
28742
28743           function selectPreLink(scope, element, attr, ctrls) {
28744
28745               // if ngModel is not defined, we don't need to do anything
28746               var ngModelCtrl = ctrls[1];
28747               if (!ngModelCtrl) return;
28748
28749               var selectCtrl = ctrls[0];
28750
28751               selectCtrl.ngModelCtrl = ngModelCtrl;
28752
28753               // We delegate rendering to the `writeValue` method, which can be changed
28754               // if the select can have multiple selected values or if the options are being
28755               // generated by `ngOptions`
28756               ngModelCtrl.$render = function() {
28757                 selectCtrl.writeValue(ngModelCtrl.$viewValue);
28758               };
28759
28760               // When the selected item(s) changes we delegate getting the value of the select control
28761               // to the `readValue` method, which can be changed if the select can have multiple
28762               // selected values or if the options are being generated by `ngOptions`
28763               element.on('change', function() {
28764                 scope.$apply(function() {
28765                   ngModelCtrl.$setViewValue(selectCtrl.readValue());
28766                 });
28767               });
28768
28769               // If the select allows multiple values then we need to modify how we read and write
28770               // values from and to the control; also what it means for the value to be empty and
28771               // we have to add an extra watch since ngModel doesn't work well with arrays - it
28772               // doesn't trigger rendering if only an item in the array changes.
28773               if (attr.multiple) {
28774
28775                 // Read value now needs to check each option to see if it is selected
28776                 selectCtrl.readValue = function readMultipleValue() {
28777                   var array = [];
28778                   forEach(element.find('option'), function(option) {
28779                     if (option.selected) {
28780                       array.push(option.value);
28781                     }
28782                   });
28783                   return array;
28784                 };
28785
28786                 // Write value now needs to set the selected property of each matching option
28787                 selectCtrl.writeValue = function writeMultipleValue(value) {
28788                   var items = new HashMap(value);
28789                   forEach(element.find('option'), function(option) {
28790                     option.selected = isDefined(items.get(option.value));
28791                   });
28792                 };
28793
28794                 // we have to do it on each watch since ngModel watches reference, but
28795                 // we need to work of an array, so we need to see if anything was inserted/removed
28796                 var lastView, lastViewRef = NaN;
28797                 scope.$watch(function selectMultipleWatch() {
28798                   if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
28799                     lastView = shallowCopy(ngModelCtrl.$viewValue);
28800                     ngModelCtrl.$render();
28801                   }
28802                   lastViewRef = ngModelCtrl.$viewValue;
28803                 });
28804
28805                 // If we are a multiple select then value is now a collection
28806                 // so the meaning of $isEmpty changes
28807                 ngModelCtrl.$isEmpty = function(value) {
28808                   return !value || value.length === 0;
28809                 };
28810
28811               }
28812             }
28813         };
28814
28815
28816         // The option directive is purely designed to communicate the existence (or lack of)
28817         // of dynamically created (and destroyed) option elements to their containing select
28818         // directive via its controller.
28819         var optionDirective = ['$interpolate', function($interpolate) {
28820           return {
28821             restrict: 'E',
28822             priority: 100,
28823             compile: function(element, attr) {
28824
28825               if (isDefined(attr.value)) {
28826                 // If the value attribute is defined, check if it contains an interpolation
28827                 var interpolateValueFn = $interpolate(attr.value, true);
28828               } else {
28829                 // If the value attribute is not defined then we fall back to the
28830                 // text content of the option element, which may be interpolated
28831                 var interpolateTextFn = $interpolate(element.text(), true);
28832                 if (!interpolateTextFn) {
28833                   attr.$set('value', element.text());
28834                 }
28835               }
28836
28837               return function(scope, element, attr) {
28838
28839                 // This is an optimization over using ^^ since we don't want to have to search
28840                 // all the way to the root of the DOM for every single option element
28841                 var selectCtrlName = '$selectController',
28842                     parent = element.parent(),
28843                     selectCtrl = parent.data(selectCtrlName) ||
28844                       parent.parent().data(selectCtrlName); // in case we are in optgroup
28845
28846                 if (selectCtrl) {
28847                   selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
28848                 }
28849               };
28850             }
28851           };
28852         }];
28853
28854         var styleDirective = valueFn({
28855           restrict: 'E',
28856           terminal: false
28857         });
28858
28859         var requiredDirective = function() {
28860           return {
28861             restrict: 'A',
28862             require: '?ngModel',
28863             link: function(scope, elm, attr, ctrl) {
28864               if (!ctrl) return;
28865               attr.required = true; // force truthy in case we are on non input element
28866
28867               ctrl.$validators.required = function(modelValue, viewValue) {
28868                 return !attr.required || !ctrl.$isEmpty(viewValue);
28869               };
28870
28871               attr.$observe('required', function() {
28872                 ctrl.$validate();
28873               });
28874             }
28875           };
28876         };
28877
28878
28879         var patternDirective = function() {
28880           return {
28881             restrict: 'A',
28882             require: '?ngModel',
28883             link: function(scope, elm, attr, ctrl) {
28884               if (!ctrl) return;
28885
28886               var regexp, patternExp = attr.ngPattern || attr.pattern;
28887               attr.$observe('pattern', function(regex) {
28888                 if (isString(regex) && regex.length > 0) {
28889                   regex = new RegExp('^' + regex + '$');
28890                 }
28891
28892                 if (regex && !regex.test) {
28893                   throw minErr('ngPattern')('noregexp',
28894                     'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
28895                     regex, startingTag(elm));
28896                 }
28897
28898                 regexp = regex || undefined;
28899                 ctrl.$validate();
28900               });
28901
28902               ctrl.$validators.pattern = function(modelValue, viewValue) {
28903                 // HTML5 pattern constraint validates the input value, so we validate the viewValue
28904                 return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
28905               };
28906             }
28907           };
28908         };
28909
28910
28911         var maxlengthDirective = function() {
28912           return {
28913             restrict: 'A',
28914             require: '?ngModel',
28915             link: function(scope, elm, attr, ctrl) {
28916               if (!ctrl) return;
28917
28918               var maxlength = -1;
28919               attr.$observe('maxlength', function(value) {
28920                 var intVal = toInt(value);
28921                 maxlength = isNaN(intVal) ? -1 : intVal;
28922                 ctrl.$validate();
28923               });
28924               ctrl.$validators.maxlength = function(modelValue, viewValue) {
28925                 return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
28926               };
28927             }
28928           };
28929         };
28930
28931         var minlengthDirective = function() {
28932           return {
28933             restrict: 'A',
28934             require: '?ngModel',
28935             link: function(scope, elm, attr, ctrl) {
28936               if (!ctrl) return;
28937
28938               var minlength = 0;
28939               attr.$observe('minlength', function(value) {
28940                 minlength = toInt(value) || 0;
28941                 ctrl.$validate();
28942               });
28943               ctrl.$validators.minlength = function(modelValue, viewValue) {
28944                 return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
28945               };
28946             }
28947           };
28948         };
28949
28950         if (window.angular.bootstrap) {
28951           //AngularJS is already loaded, so we can return here...
28952           console.log('WARNING: Tried to load angular more than once.');
28953           return;
28954         }
28955
28956         //try to bind to jquery now so that one can write jqLite(document).ready()
28957         //but we will rebind on bootstrap again.
28958         bindJQuery();
28959
28960         publishExternalAPI(angular);
28961
28962         angular.module("ngLocale", [], ["$provide", function($provide) {
28963         var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
28964         function getDecimals(n) {
28965           n = n + '';
28966           var i = n.indexOf('.');
28967           return (i == -1) ? 0 : n.length - i - 1;
28968         }
28969
28970         function getVF(n, opt_precision) {
28971           var v = opt_precision;
28972
28973           if (undefined === v) {
28974             v = Math.min(getDecimals(n), 3);
28975           }
28976
28977           var base = Math.pow(10, v);
28978           var f = ((n * base) | 0) % base;
28979           return {v: v, f: f};
28980         }
28981
28982         $provide.value("$locale", {
28983           "DATETIME_FORMATS": {
28984             "AMPMS": [
28985               "AM",
28986               "PM"
28987             ],
28988             "DAY": [
28989               "Sunday",
28990               "Monday",
28991               "Tuesday",
28992               "Wednesday",
28993               "Thursday",
28994               "Friday",
28995               "Saturday"
28996             ],
28997             "ERANAMES": [
28998               "Before Christ",
28999               "Anno Domini"
29000             ],
29001             "ERAS": [
29002               "BC",
29003               "AD"
29004             ],
29005             "FIRSTDAYOFWEEK": 6,
29006             "MONTH": [
29007               "January",
29008               "February",
29009               "March",
29010               "April",
29011               "May",
29012               "June",
29013               "July",
29014               "August",
29015               "September",
29016               "October",
29017               "November",
29018               "December"
29019             ],
29020             "SHORTDAY": [
29021               "Sun",
29022               "Mon",
29023               "Tue",
29024               "Wed",
29025               "Thu",
29026               "Fri",
29027               "Sat"
29028             ],
29029             "SHORTMONTH": [
29030               "Jan",
29031               "Feb",
29032               "Mar",
29033               "Apr",
29034               "May",
29035               "Jun",
29036               "Jul",
29037               "Aug",
29038               "Sep",
29039               "Oct",
29040               "Nov",
29041               "Dec"
29042             ],
29043             "WEEKENDRANGE": [
29044               5,
29045               6
29046             ],
29047             "fullDate": "EEEE, MMMM d, y",
29048             "longDate": "MMMM d, y",
29049             "medium": "MMM d, y h:mm:ss a",
29050             "mediumDate": "MMM d, y",
29051             "mediumTime": "h:mm:ss a",
29052             "short": "M/d/yy h:mm a",
29053             "shortDate": "M/d/yy",
29054             "shortTime": "h:mm a"
29055           },
29056           "NUMBER_FORMATS": {
29057             "CURRENCY_SYM": "$",
29058             "DECIMAL_SEP": ".",
29059             "GROUP_SEP": ",",
29060             "PATTERNS": [
29061               {
29062                 "gSize": 3,
29063                 "lgSize": 3,
29064                 "maxFrac": 3,
29065                 "minFrac": 0,
29066                 "minInt": 1,
29067                 "negPre": "-",
29068                 "negSuf": "",
29069                 "posPre": "",
29070                 "posSuf": ""
29071               },
29072               {
29073                 "gSize": 3,
29074                 "lgSize": 3,
29075                 "maxFrac": 2,
29076                 "minFrac": 2,
29077                 "minInt": 1,
29078                 "negPre": "-\u00a4",
29079                 "negSuf": "",
29080                 "posPre": "\u00a4",
29081                 "posSuf": ""
29082               }
29083             ]
29084           },
29085           "id": "en-us",
29086           "pluralCat": function(n, opt_precision) {  var i = n | 0;  var vf = getVF(n, opt_precision);  if (i == 1 && vf.v == 0) {    return PLURAL_CATEGORY.ONE;  }  return PLURAL_CATEGORY.OTHER;}
29087         });
29088         }]);
29089
29090           jqLite(document).ready(function() {
29091             angularInit(document, bootstrap);
29092           });
29093
29094         })(window, document);
29095
29096         !window.angular.$$csp().noInlineStyle && window.angular.element(document.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:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
29097
29098 /***/ },
29099 /* 3 */
29100 /***/ function(module, exports) {
29101
29102         /**
29103          * State-based routing for AngularJS
29104          * @version v0.2.15
29105          * @link http://angular-ui.github.com/
29106          * @license MIT License, http://www.opensource.org/licenses/MIT
29107          */
29108
29109         /* commonjs package manager support (eg componentjs) */
29110         if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
29111           module.exports = 'ui.router';
29112         }
29113
29114         (function (window, angular, undefined) {
29115         /*jshint globalstrict:true*/
29116         /*global angular:false*/
29117         'use strict';
29118
29119         var isDefined = angular.isDefined,
29120             isFunction = angular.isFunction,
29121             isString = angular.isString,
29122             isObject = angular.isObject,
29123             isArray = angular.isArray,
29124             forEach = angular.forEach,
29125             extend = angular.extend,
29126             copy = angular.copy;
29127
29128         function inherit(parent, extra) {
29129           return extend(new (extend(function() {}, { prototype: parent }))(), extra);
29130         }
29131
29132         function merge(dst) {
29133           forEach(arguments, function(obj) {
29134             if (obj !== dst) {
29135               forEach(obj, function(value, key) {
29136                 if (!dst.hasOwnProperty(key)) dst[key] = value;
29137               });
29138             }
29139           });
29140           return dst;
29141         }
29142
29143         /**
29144          * Finds the common ancestor path between two states.
29145          *
29146          * @param {Object} first The first state.
29147          * @param {Object} second The second state.
29148          * @return {Array} Returns an array of state names in descending order, not including the root.
29149          */
29150         function ancestors(first, second) {
29151           var path = [];
29152
29153           for (var n in first.path) {
29154             if (first.path[n] !== second.path[n]) break;
29155             path.push(first.path[n]);
29156           }
29157           return path;
29158         }
29159
29160         /**
29161          * IE8-safe wrapper for `Object.keys()`.
29162          *
29163          * @param {Object} object A JavaScript object.
29164          * @return {Array} Returns the keys of the object as an array.
29165          */
29166         function objectKeys(object) {
29167           if (Object.keys) {
29168             return Object.keys(object);
29169           }
29170           var result = [];
29171
29172           forEach(object, function(val, key) {
29173             result.push(key);
29174           });
29175           return result;
29176         }
29177
29178         /**
29179          * IE8-safe wrapper for `Array.prototype.indexOf()`.
29180          *
29181          * @param {Array} array A JavaScript array.
29182          * @param {*} value A value to search the array for.
29183          * @return {Number} Returns the array index value of `value`, or `-1` if not present.
29184          */
29185         function indexOf(array, value) {
29186           if (Array.prototype.indexOf) {
29187             return array.indexOf(value, Number(arguments[2]) || 0);
29188           }
29189           var len = array.length >>> 0, from = Number(arguments[2]) || 0;
29190           from = (from < 0) ? Math.ceil(from) : Math.floor(from);
29191
29192           if (from < 0) from += len;
29193
29194           for (; from < len; from++) {
29195             if (from in array && array[from] === value) return from;
29196           }
29197           return -1;
29198         }
29199
29200         /**
29201          * Merges a set of parameters with all parameters inherited between the common parents of the
29202          * current state and a given destination state.
29203          *
29204          * @param {Object} currentParams The value of the current state parameters ($stateParams).
29205          * @param {Object} newParams The set of parameters which will be composited with inherited params.
29206          * @param {Object} $current Internal definition of object representing the current state.
29207          * @param {Object} $to Internal definition of object representing state to transition to.
29208          */
29209         function inheritParams(currentParams, newParams, $current, $to) {
29210           var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];
29211
29212           for (var i in parents) {
29213             if (!parents[i].params) continue;
29214             parentParams = objectKeys(parents[i].params);
29215             if (!parentParams.length) continue;
29216
29217             for (var j in parentParams) {
29218               if (indexOf(inheritList, parentParams[j]) >= 0) continue;
29219               inheritList.push(parentParams[j]);
29220               inherited[parentParams[j]] = currentParams[parentParams[j]];
29221             }
29222           }
29223           return extend({}, inherited, newParams);
29224         }
29225
29226         /**
29227          * Performs a non-strict comparison of the subset of two objects, defined by a list of keys.
29228          *
29229          * @param {Object} a The first object.
29230          * @param {Object} b The second object.
29231          * @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified,
29232          *                     it defaults to the list of keys in `a`.
29233          * @return {Boolean} Returns `true` if the keys match, otherwise `false`.
29234          */
29235         function equalForKeys(a, b, keys) {
29236           if (!keys) {
29237             keys = [];
29238             for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
29239           }
29240
29241           for (var i=0; i<keys.length; i++) {
29242             var k = keys[i];
29243             if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
29244           }
29245           return true;
29246         }
29247
29248         /**
29249          * Returns the subset of an object, based on a list of keys.
29250          *
29251          * @param {Array} keys
29252          * @param {Object} values
29253          * @return {Boolean} Returns a subset of `values`.
29254          */
29255         function filterByKeys(keys, values) {
29256           var filtered = {};
29257
29258           forEach(keys, function (name) {
29259             filtered[name] = values[name];
29260           });
29261           return filtered;
29262         }
29263
29264         // like _.indexBy
29265         // when you know that your index values will be unique, or you want last-one-in to win
29266         function indexBy(array, propName) {
29267           var result = {};
29268           forEach(array, function(item) {
29269             result[item[propName]] = item;
29270           });
29271           return result;
29272         }
29273
29274         // extracted from underscore.js
29275         // Return a copy of the object only containing the whitelisted properties.
29276         function pick(obj) {
29277           var copy = {};
29278           var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
29279           forEach(keys, function(key) {
29280             if (key in obj) copy[key] = obj[key];
29281           });
29282           return copy;
29283         }
29284
29285         // extracted from underscore.js
29286         // Return a copy of the object omitting the blacklisted properties.
29287         function omit(obj) {
29288           var copy = {};
29289           var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
29290           for (var key in obj) {
29291             if (indexOf(keys, key) == -1) copy[key] = obj[key];
29292           }
29293           return copy;
29294         }
29295
29296         function pluck(collection, key) {
29297           var result = isArray(collection) ? [] : {};
29298
29299           forEach(collection, function(val, i) {
29300             result[i] = isFunction(key) ? key(val) : val[key];
29301           });
29302           return result;
29303         }
29304
29305         function filter(collection, callback) {
29306           var array = isArray(collection);
29307           var result = array ? [] : {};
29308           forEach(collection, function(val, i) {
29309             if (callback(val, i)) {
29310               result[array ? result.length : i] = val;
29311             }
29312           });
29313           return result;
29314         }
29315
29316         function map(collection, callback) {
29317           var result = isArray(collection) ? [] : {};
29318
29319           forEach(collection, function(val, i) {
29320             result[i] = callback(val, i);
29321           });
29322           return result;
29323         }
29324
29325         /**
29326          * @ngdoc overview
29327          * @name ui.router.util
29328          *
29329          * @description
29330          * # ui.router.util sub-module
29331          *
29332          * This module is a dependency of other sub-modules. Do not include this module as a dependency
29333          * in your angular app (use {@link ui.router} module instead).
29334          *
29335          */
29336         angular.module('ui.router.util', ['ng']);
29337
29338         /**
29339          * @ngdoc overview
29340          * @name ui.router.router
29341          * 
29342          * @requires ui.router.util
29343          *
29344          * @description
29345          * # ui.router.router sub-module
29346          *
29347          * This module is a dependency of other sub-modules. Do not include this module as a dependency
29348          * in your angular app (use {@link ui.router} module instead).
29349          */
29350         angular.module('ui.router.router', ['ui.router.util']);
29351
29352         /**
29353          * @ngdoc overview
29354          * @name ui.router.state
29355          * 
29356          * @requires ui.router.router
29357          * @requires ui.router.util
29358          *
29359          * @description
29360          * # ui.router.state sub-module
29361          *
29362          * This module is a dependency of the main ui.router module. Do not include this module as a dependency
29363          * in your angular app (use {@link ui.router} module instead).
29364          * 
29365          */
29366         angular.module('ui.router.state', ['ui.router.router', 'ui.router.util']);
29367
29368         /**
29369          * @ngdoc overview
29370          * @name ui.router
29371          *
29372          * @requires ui.router.state
29373          *
29374          * @description
29375          * # ui.router
29376          * 
29377          * ## The main module for ui.router 
29378          * There are several sub-modules included with the ui.router module, however only this module is needed
29379          * as a dependency within your angular app. The other modules are for organization purposes. 
29380          *
29381          * The modules are:
29382          * * ui.router - the main "umbrella" module
29383          * * ui.router.router - 
29384          * 
29385          * *You'll need to include **only** this module as the dependency within your angular app.*
29386          * 
29387          * <pre>
29388          * <!doctype html>
29389          * <html ng-app="myApp">
29390          * <head>
29391          *   <script src="js/angular.js"></script>
29392          *   <!-- Include the ui-router script -->
29393          *   <script src="js/angular-ui-router.min.js"></script>
29394          *   <script>
29395          *     // ...and add 'ui.router' as a dependency
29396          *     var myApp = angular.module('myApp', ['ui.router']);
29397          *   </script>
29398          * </head>
29399          * <body>
29400          * </body>
29401          * </html>
29402          * </pre>
29403          */
29404         angular.module('ui.router', ['ui.router.state']);
29405
29406         angular.module('ui.router.compat', ['ui.router']);
29407
29408         /**
29409          * @ngdoc object
29410          * @name ui.router.util.$resolve
29411          *
29412          * @requires $q
29413          * @requires $injector
29414          *
29415          * @description
29416          * Manages resolution of (acyclic) graphs of promises.
29417          */
29418         $Resolve.$inject = ['$q', '$injector'];
29419         function $Resolve(  $q,    $injector) {
29420           
29421           var VISIT_IN_PROGRESS = 1,
29422               VISIT_DONE = 2,
29423               NOTHING = {},
29424               NO_DEPENDENCIES = [],
29425               NO_LOCALS = NOTHING,
29426               NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });
29427           
29428
29429           /**
29430            * @ngdoc function
29431            * @name ui.router.util.$resolve#study
29432            * @methodOf ui.router.util.$resolve
29433            *
29434            * @description
29435            * Studies a set of invocables that are likely to be used multiple times.
29436            * <pre>
29437            * $resolve.study(invocables)(locals, parent, self)
29438            * </pre>
29439            * is equivalent to
29440            * <pre>
29441            * $resolve.resolve(invocables, locals, parent, self)
29442            * </pre>
29443            * but the former is more efficient (in fact `resolve` just calls `study` 
29444            * internally).
29445            *
29446            * @param {object} invocables Invocable objects
29447            * @return {function} a function to pass in locals, parent and self
29448            */
29449           this.study = function (invocables) {
29450             if (!isObject(invocables)) throw new Error("'invocables' must be an object");
29451             var invocableKeys = objectKeys(invocables || {});
29452             
29453             // Perform a topological sort of invocables to build an ordered plan
29454             var plan = [], cycle = [], visited = {};
29455             function visit(value, key) {
29456               if (visited[key] === VISIT_DONE) return;
29457               
29458               cycle.push(key);
29459               if (visited[key] === VISIT_IN_PROGRESS) {
29460                 cycle.splice(0, indexOf(cycle, key));
29461                 throw new Error("Cyclic dependency: " + cycle.join(" -> "));
29462               }
29463               visited[key] = VISIT_IN_PROGRESS;
29464               
29465               if (isString(value)) {
29466                 plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
29467               } else {
29468                 var params = $injector.annotate(value);
29469                 forEach(params, function (param) {
29470                   if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);
29471                 });
29472                 plan.push(key, value, params);
29473               }
29474               
29475               cycle.pop();
29476               visited[key] = VISIT_DONE;
29477             }
29478             forEach(invocables, visit);
29479             invocables = cycle = visited = null; // plan is all that's required
29480             
29481             function isResolve(value) {
29482               return isObject(value) && value.then && value.$$promises;
29483             }
29484             
29485             return function (locals, parent, self) {
29486               if (isResolve(locals) && self === undefined) {
29487                 self = parent; parent = locals; locals = null;
29488               }
29489               if (!locals) locals = NO_LOCALS;
29490               else if (!isObject(locals)) {
29491                 throw new Error("'locals' must be an object");
29492               }       
29493               if (!parent) parent = NO_PARENT;
29494               else if (!isResolve(parent)) {
29495                 throw new Error("'parent' must be a promise returned by $resolve.resolve()");
29496               }
29497               
29498               // To complete the overall resolution, we have to wait for the parent
29499               // promise and for the promise for each invokable in our plan.
29500               var resolution = $q.defer(),
29501                   result = resolution.promise,
29502                   promises = result.$$promises = {},
29503                   values = extend({}, locals),
29504                   wait = 1 + plan.length/3,
29505                   merged = false;
29506                   
29507               function done() {
29508                 // Merge parent values we haven't got yet and publish our own $$values
29509                 if (!--wait) {
29510                   if (!merged) merge(values, parent.$$values); 
29511                   result.$$values = values;
29512                   result.$$promises = result.$$promises || true; // keep for isResolve()
29513                   delete result.$$inheritedValues;
29514                   resolution.resolve(values);
29515                 }
29516               }
29517               
29518               function fail(reason) {
29519                 result.$$failure = reason;
29520                 resolution.reject(reason);
29521               }
29522
29523               // Short-circuit if parent has already failed
29524               if (isDefined(parent.$$failure)) {
29525                 fail(parent.$$failure);
29526                 return result;
29527               }
29528               
29529               if (parent.$$inheritedValues) {
29530                 merge(values, omit(parent.$$inheritedValues, invocableKeys));
29531               }
29532
29533               // Merge parent values if the parent has already resolved, or merge
29534               // parent promises and wait if the parent resolve is still in progress.
29535               extend(promises, parent.$$promises);
29536               if (parent.$$values) {
29537                 merged = merge(values, omit(parent.$$values, invocableKeys));
29538                 result.$$inheritedValues = omit(parent.$$values, invocableKeys);
29539                 done();
29540               } else {
29541                 if (parent.$$inheritedValues) {
29542                   result.$$inheritedValues = omit(parent.$$inheritedValues, invocableKeys);
29543                 }        
29544                 parent.then(done, fail);
29545               }
29546               
29547               // Process each invocable in the plan, but ignore any where a local of the same name exists.
29548               for (var i=0, ii=plan.length; i<ii; i+=3) {
29549                 if (locals.hasOwnProperty(plan[i])) done();
29550                 else invoke(plan[i], plan[i+1], plan[i+2]);
29551               }
29552               
29553               function invoke(key, invocable, params) {
29554                 // Create a deferred for this invocation. Failures will propagate to the resolution as well.
29555                 var invocation = $q.defer(), waitParams = 0;
29556                 function onfailure(reason) {
29557                   invocation.reject(reason);
29558                   fail(reason);
29559                 }
29560                 // Wait for any parameter that we have a promise for (either from parent or from this
29561                 // resolve; in that case study() will have made sure it's ordered before us in the plan).
29562                 forEach(params, function (dep) {
29563                   if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) {
29564                     waitParams++;
29565                     promises[dep].then(function (result) {
29566                       values[dep] = result;
29567                       if (!(--waitParams)) proceed();
29568                     }, onfailure);
29569                   }
29570                 });
29571                 if (!waitParams) proceed();
29572                 function proceed() {
29573                   if (isDefined(result.$$failure)) return;
29574                   try {
29575                     invocation.resolve($injector.invoke(invocable, self, values));
29576                     invocation.promise.then(function (result) {
29577                       values[key] = result;
29578                       done();
29579                     }, onfailure);
29580                   } catch (e) {
29581                     onfailure(e);
29582                   }
29583                 }
29584                 // Publish promise synchronously; invocations further down in the plan may depend on it.
29585                 promises[key] = invocation.promise;
29586               }
29587               
29588               return result;
29589             };
29590           };
29591           
29592           /**
29593            * @ngdoc function
29594            * @name ui.router.util.$resolve#resolve
29595            * @methodOf ui.router.util.$resolve
29596            *
29597            * @description
29598            * Resolves a set of invocables. An invocable is a function to be invoked via 
29599            * `$injector.invoke()`, and can have an arbitrary number of dependencies. 
29600            * An invocable can either return a value directly,
29601            * or a `$q` promise. If a promise is returned it will be resolved and the 
29602            * resulting value will be used instead. Dependencies of invocables are resolved 
29603            * (in this order of precedence)
29604            *
29605            * - from the specified `locals`
29606            * - from another invocable that is part of this `$resolve` call
29607            * - from an invocable that is inherited from a `parent` call to `$resolve` 
29608            *   (or recursively
29609            * - from any ancestor `$resolve` of that parent).
29610            *
29611            * The return value of `$resolve` is a promise for an object that contains 
29612            * (in this order of precedence)
29613            *
29614            * - any `locals` (if specified)
29615            * - the resolved return values of all injectables
29616            * - any values inherited from a `parent` call to `$resolve` (if specified)
29617            *
29618            * The promise will resolve after the `parent` promise (if any) and all promises 
29619            * returned by injectables have been resolved. If any invocable 
29620            * (or `$injector.invoke`) throws an exception, or if a promise returned by an 
29621            * invocable is rejected, the `$resolve` promise is immediately rejected with the 
29622            * same error. A rejection of a `parent` promise (if specified) will likewise be 
29623            * propagated immediately. Once the `$resolve` promise has been rejected, no 
29624            * further invocables will be called.
29625            * 
29626            * Cyclic dependencies between invocables are not permitted and will caues `$resolve`
29627            * to throw an error. As a special case, an injectable can depend on a parameter 
29628            * with the same name as the injectable, which will be fulfilled from the `parent` 
29629            * injectable of the same name. This allows inherited values to be decorated. 
29630            * Note that in this case any other injectable in the same `$resolve` with the same
29631            * dependency would see the decorated value, not the inherited value.
29632            *
29633            * Note that missing dependencies -- unlike cyclic dependencies -- will cause an 
29634            * (asynchronous) rejection of the `$resolve` promise rather than a (synchronous) 
29635            * exception.
29636            *
29637            * Invocables are invoked eagerly as soon as all dependencies are available. 
29638            * This is true even for dependencies inherited from a `parent` call to `$resolve`.
29639            *
29640            * As a special case, an invocable can be a string, in which case it is taken to 
29641            * be a service name to be passed to `$injector.get()`. This is supported primarily 
29642            * for backwards-compatibility with the `resolve` property of `$routeProvider` 
29643            * routes.
29644            *
29645            * @param {object} invocables functions to invoke or 
29646            * `$injector` services to fetch.
29647            * @param {object} locals  values to make available to the injectables
29648            * @param {object} parent  a promise returned by another call to `$resolve`.
29649            * @param {object} self  the `this` for the invoked methods
29650            * @return {object} Promise for an object that contains the resolved return value
29651            * of all invocables, as well as any inherited and local values.
29652            */
29653           this.resolve = function (invocables, locals, parent, self) {
29654             return this.study(invocables)(locals, parent, self);
29655           };
29656         }
29657
29658         angular.module('ui.router.util').service('$resolve', $Resolve);
29659
29660
29661         /**
29662          * @ngdoc object
29663          * @name ui.router.util.$templateFactory
29664          *
29665          * @requires $http
29666          * @requires $templateCache
29667          * @requires $injector
29668          *
29669          * @description
29670          * Service. Manages loading of templates.
29671          */
29672         $TemplateFactory.$inject = ['$http', '$templateCache', '$injector'];
29673         function $TemplateFactory(  $http,   $templateCache,   $injector) {
29674
29675           /**
29676            * @ngdoc function
29677            * @name ui.router.util.$templateFactory#fromConfig
29678            * @methodOf ui.router.util.$templateFactory
29679            *
29680            * @description
29681            * Creates a template from a configuration object. 
29682            *
29683            * @param {object} config Configuration object for which to load a template. 
29684            * The following properties are search in the specified order, and the first one 
29685            * that is defined is used to create the template:
29686            *
29687            * @param {string|object} config.template html string template or function to 
29688            * load via {@link ui.router.util.$templateFactory#fromString fromString}.
29689            * @param {string|object} config.templateUrl url to load or a function returning 
29690            * the url to load via {@link ui.router.util.$templateFactory#fromUrl fromUrl}.
29691            * @param {Function} config.templateProvider function to invoke via 
29692            * {@link ui.router.util.$templateFactory#fromProvider fromProvider}.
29693            * @param {object} params  Parameters to pass to the template function.
29694            * @param {object} locals Locals to pass to `invoke` if the template is loaded 
29695            * via a `templateProvider`. Defaults to `{ params: params }`.
29696            *
29697            * @return {string|object}  The template html as a string, or a promise for 
29698            * that string,or `null` if no template is configured.
29699            */
29700           this.fromConfig = function (config, params, locals) {
29701             return (
29702               isDefined(config.template) ? this.fromString(config.template, params) :
29703               isDefined(config.templateUrl) ? this.fromUrl(config.templateUrl, params) :
29704               isDefined(config.templateProvider) ? this.fromProvider(config.templateProvider, params, locals) :
29705               null
29706             );
29707           };
29708
29709           /**
29710            * @ngdoc function
29711            * @name ui.router.util.$templateFactory#fromString
29712            * @methodOf ui.router.util.$templateFactory
29713            *
29714            * @description
29715            * Creates a template from a string or a function returning a string.
29716            *
29717            * @param {string|object} template html template as a string or function that 
29718            * returns an html template as a string.
29719            * @param {object} params Parameters to pass to the template function.
29720            *
29721            * @return {string|object} The template html as a string, or a promise for that 
29722            * string.
29723            */
29724           this.fromString = function (template, params) {
29725             return isFunction(template) ? template(params) : template;
29726           };
29727
29728           /**
29729            * @ngdoc function
29730            * @name ui.router.util.$templateFactory#fromUrl
29731            * @methodOf ui.router.util.$templateFactory
29732            * 
29733            * @description
29734            * Loads a template from the a URL via `$http` and `$templateCache`.
29735            *
29736            * @param {string|Function} url url of the template to load, or a function 
29737            * that returns a url.
29738            * @param {Object} params Parameters to pass to the url function.
29739            * @return {string|Promise.<string>} The template html as a string, or a promise 
29740            * for that string.
29741            */
29742           this.fromUrl = function (url, params) {
29743             if (isFunction(url)) url = url(params);
29744             if (url == null) return null;
29745             else return $http
29746                 .get(url, { cache: $templateCache, headers: { Accept: 'text/html' }})
29747                 .then(function(response) { return response.data; });
29748           };
29749
29750           /**
29751            * @ngdoc function
29752            * @name ui.router.util.$templateFactory#fromProvider
29753            * @methodOf ui.router.util.$templateFactory
29754            *
29755            * @description
29756            * Creates a template by invoking an injectable provider function.
29757            *
29758            * @param {Function} provider Function to invoke via `$injector.invoke`
29759            * @param {Object} params Parameters for the template.
29760            * @param {Object} locals Locals to pass to `invoke`. Defaults to 
29761            * `{ params: params }`.
29762            * @return {string|Promise.<string>} The template html as a string, or a promise 
29763            * for that string.
29764            */
29765           this.fromProvider = function (provider, params, locals) {
29766             return $injector.invoke(provider, null, locals || { params: params });
29767           };
29768         }
29769
29770         angular.module('ui.router.util').service('$templateFactory', $TemplateFactory);
29771
29772         var $$UMFP; // reference to $UrlMatcherFactoryProvider
29773
29774         /**
29775          * @ngdoc object
29776          * @name ui.router.util.type:UrlMatcher
29777          *
29778          * @description
29779          * Matches URLs against patterns and extracts named parameters from the path or the search
29780          * part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list
29781          * of search parameters. Multiple search parameter names are separated by '&'. Search parameters
29782          * do not influence whether or not a URL is matched, but their values are passed through into
29783          * the matched parameters returned by {@link ui.router.util.type:UrlMatcher#methods_exec exec}.
29784          *
29785          * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
29786          * syntax, which optionally allows a regular expression for the parameter to be specified:
29787          *
29788          * * `':'` name - colon placeholder
29789          * * `'*'` name - catch-all placeholder
29790          * * `'{' name '}'` - curly placeholder
29791          * * `'{' name ':' regexp|type '}'` - curly placeholder with regexp or type name. Should the
29792          *   regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash.
29793          *
29794          * Parameter names may contain only word characters (latin letters, digits, and underscore) and
29795          * must be unique within the pattern (across both path and search parameters). For colon
29796          * placeholders or curly placeholders without an explicit regexp, a path parameter matches any
29797          * number of characters other than '/'. For catch-all placeholders the path parameter matches
29798          * any number of characters.
29799          *
29800          * Examples:
29801          *
29802          * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for
29803          *   trailing slashes, and patterns have to match the entire path, not just a prefix.
29804          * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
29805          *   '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
29806          * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax.
29807          * * `'/user/{id:[^/]*}'` - Same as the previous example.
29808          * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id
29809          *   parameter consists of 1 to 8 hex digits.
29810          * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the
29811          *   path into the parameter 'path'.
29812          * * `'/files/*path'` - ditto.
29813          * * `'/calendar/{start:date}'` - Matches "/calendar/2014-11-12" (because the pattern defined
29814          *   in the built-in  `date` Type matches `2014-11-12`) and provides a Date object in $stateParams.start
29815          *
29816          * @param {string} pattern  The pattern to compile into a matcher.
29817          * @param {Object} config  A configuration object hash:
29818          * @param {Object=} parentMatcher Used to concatenate the pattern/config onto
29819          *   an existing UrlMatcher
29820          *
29821          * * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.
29822          * * `strict` - `false` if matching against a URL with a trailing slash should be treated as equivalent to a URL without a trailing slash, the default value is `true`.
29823          *
29824          * @property {string} prefix  A static prefix of this pattern. The matcher guarantees that any
29825          *   URL matching this matcher (i.e. any string for which {@link ui.router.util.type:UrlMatcher#methods_exec exec()} returns
29826          *   non-null) will start with this prefix.
29827          *
29828          * @property {string} source  The pattern that was passed into the constructor
29829          *
29830          * @property {string} sourcePath  The path portion of the source property
29831          *
29832          * @property {string} sourceSearch  The search portion of the source property
29833          *
29834          * @property {string} regex  The constructed regex that will be used to match against the url when
29835          *   it is time to determine which url will match.
29836          *
29837          * @returns {Object}  New `UrlMatcher` object
29838          */
29839         function UrlMatcher(pattern, config, parentMatcher) {
29840           config = extend({ params: {} }, isObject(config) ? config : {});
29841
29842           // Find all placeholders and create a compiled pattern, using either classic or curly syntax:
29843           //   '*' name
29844           //   ':' name
29845           //   '{' name '}'
29846           //   '{' name ':' regexp '}'
29847           // The regular expression is somewhat complicated due to the need to allow curly braces
29848           // inside the regular expression. The placeholder regexp breaks down as follows:
29849           //    ([:*])([\w\[\]]+)              - classic placeholder ($1 / $2) (search version has - for snake-case)
29850           //    \{([\w\[\]]+)(?:\:( ... ))?\}  - curly brace placeholder ($3) with optional regexp/type ... ($4) (search version has - for snake-case
29851           //    (?: ... | ... | ... )+         - the regexp consists of any number of atoms, an atom being either
29852           //    [^{}\\]+                       - anything other than curly braces or backslash
29853           //    \\.                            - a backslash escape
29854           //    \{(?:[^{}\\]+|\\.)*\}          - a matched set of curly braces containing other atoms
29855           var placeholder       = /([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
29856               searchPlaceholder = /([:]?)([\w\[\]-]+)|\{([\w\[\]-]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
29857               compiled = '^', last = 0, m,
29858               segments = this.segments = [],
29859               parentParams = parentMatcher ? parentMatcher.params : {},
29860               params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet(),
29861               paramNames = [];
29862
29863           function addParameter(id, type, config, location) {
29864             paramNames.push(id);
29865             if (parentParams[id]) return parentParams[id];
29866             if (!/^\w+(-+\w+)*(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
29867             if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
29868             params[id] = new $$UMFP.Param(id, type, config, location);
29869             return params[id];
29870           }
29871
29872           function quoteRegExp(string, pattern, squash, optional) {
29873             var surroundPattern = ['',''], result = string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
29874             if (!pattern) return result;
29875             switch(squash) {
29876               case false: surroundPattern = ['(', ')' + (optional ? "?" : "")]; break;
29877               case true:  surroundPattern = ['?(', ')?']; break;
29878               default:    surroundPattern = ['(' + squash + "|", ')?']; break;
29879             }
29880             return result + surroundPattern[0] + pattern + surroundPattern[1];
29881           }
29882
29883           this.source = pattern;
29884
29885           // Split into static segments separated by path parameter placeholders.
29886           // The number of segments is always 1 more than the number of parameters.
29887           function matchDetails(m, isSearch) {
29888             var id, regexp, segment, type, cfg, arrayMode;
29889             id          = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
29890             cfg         = config.params[id];
29891             segment     = pattern.substring(last, m.index);
29892             regexp      = isSearch ? m[4] : m[4] || (m[1] == '*' ? '.*' : null);
29893             type        = $$UMFP.type(regexp || "string") || inherit($$UMFP.type("string"), { pattern: new RegExp(regexp, config.caseInsensitive ? 'i' : undefined) });
29894             return {
29895               id: id, regexp: regexp, segment: segment, type: type, cfg: cfg
29896             };
29897           }
29898
29899           var p, param, segment;
29900           while ((m = placeholder.exec(pattern))) {
29901             p = matchDetails(m, false);
29902             if (p.segment.indexOf('?') >= 0) break; // we're into the search part
29903
29904             param = addParameter(p.id, p.type, p.cfg, "path");
29905             compiled += quoteRegExp(p.segment, param.type.pattern.source, param.squash, param.isOptional);
29906             segments.push(p.segment);
29907             last = placeholder.lastIndex;
29908           }
29909           segment = pattern.substring(last);
29910
29911           // Find any search parameter names and remove them from the last segment
29912           var i = segment.indexOf('?');
29913
29914           if (i >= 0) {
29915             var search = this.sourceSearch = segment.substring(i);
29916             segment = segment.substring(0, i);
29917             this.sourcePath = pattern.substring(0, last + i);
29918
29919             if (search.length > 0) {
29920               last = 0;
29921               while ((m = searchPlaceholder.exec(search))) {
29922                 p = matchDetails(m, true);
29923                 param = addParameter(p.id, p.type, p.cfg, "search");
29924                 last = placeholder.lastIndex;
29925                 // check if ?&
29926               }
29927             }
29928           } else {
29929             this.sourcePath = pattern;
29930             this.sourceSearch = '';
29931           }
29932
29933           compiled += quoteRegExp(segment) + (config.strict === false ? '\/?' : '') + '$';
29934           segments.push(segment);
29935
29936           this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined);
29937           this.prefix = segments[0];
29938           this.$$paramNames = paramNames;
29939         }
29940
29941         /**
29942          * @ngdoc function
29943          * @name ui.router.util.type:UrlMatcher#concat
29944          * @methodOf ui.router.util.type:UrlMatcher
29945          *
29946          * @description
29947          * Returns a new matcher for a pattern constructed by appending the path part and adding the
29948          * search parameters of the specified pattern to this pattern. The current pattern is not
29949          * modified. This can be understood as creating a pattern for URLs that are relative to (or
29950          * suffixes of) the current pattern.
29951          *
29952          * @example
29953          * The following two matchers are equivalent:
29954          * <pre>
29955          * new UrlMatcher('/user/{id}?q').concat('/details?date');
29956          * new UrlMatcher('/user/{id}/details?q&date');
29957          * </pre>
29958          *
29959          * @param {string} pattern  The pattern to append.
29960          * @param {Object} config  An object hash of the configuration for the matcher.
29961          * @returns {UrlMatcher}  A matcher for the concatenated pattern.
29962          */
29963         UrlMatcher.prototype.concat = function (pattern, config) {
29964           // Because order of search parameters is irrelevant, we can add our own search
29965           // parameters to the end of the new pattern. Parse the new pattern by itself
29966           // and then join the bits together, but it's much easier to do this on a string level.
29967           var defaultConfig = {
29968             caseInsensitive: $$UMFP.caseInsensitive(),
29969             strict: $$UMFP.strictMode(),
29970             squash: $$UMFP.defaultSquashPolicy()
29971           };
29972           return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, extend(defaultConfig, config), this);
29973         };
29974
29975         UrlMatcher.prototype.toString = function () {
29976           return this.source;
29977         };
29978
29979         /**
29980          * @ngdoc function
29981          * @name ui.router.util.type:UrlMatcher#exec
29982          * @methodOf ui.router.util.type:UrlMatcher
29983          *
29984          * @description
29985          * Tests the specified path against this matcher, and returns an object containing the captured
29986          * parameter values, or null if the path does not match. The returned object contains the values
29987          * of any search parameters that are mentioned in the pattern, but their value may be null if
29988          * they are not present in `searchParams`. This means that search parameters are always treated
29989          * as optional.
29990          *
29991          * @example
29992          * <pre>
29993          * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', {
29994          *   x: '1', q: 'hello'
29995          * });
29996          * // returns { id: 'bob', q: 'hello', r: null }
29997          * </pre>
29998          *
29999          * @param {string} path  The URL path to match, e.g. `$location.path()`.
30000          * @param {Object} searchParams  URL search parameters, e.g. `$location.search()`.
30001          * @returns {Object}  The captured parameter values.
30002          */
30003         UrlMatcher.prototype.exec = function (path, searchParams) {
30004           var m = this.regexp.exec(path);
30005           if (!m) return null;
30006           searchParams = searchParams || {};
30007
30008           var paramNames = this.parameters(), nTotal = paramNames.length,
30009             nPath = this.segments.length - 1,
30010             values = {}, i, j, cfg, paramName;
30011
30012           if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'");
30013
30014           function decodePathArray(string) {
30015             function reverseString(str) { return str.split("").reverse().join(""); }
30016             function unquoteDashes(str) { return str.replace(/\\-/g, "-"); }
30017
30018             var split = reverseString(string).split(/-(?!\\)/);
30019             var allReversed = map(split, reverseString);
30020             return map(allReversed, unquoteDashes).reverse();
30021           }
30022
30023           for (i = 0; i < nPath; i++) {
30024             paramName = paramNames[i];
30025             var param = this.params[paramName];
30026             var paramVal = m[i+1];
30027             // if the param value matches a pre-replace pair, replace the value before decoding.
30028             for (j = 0; j < param.replace; j++) {
30029               if (param.replace[j].from === paramVal) paramVal = param.replace[j].to;
30030             }
30031             if (paramVal && param.array === true) paramVal = decodePathArray(paramVal);
30032             values[paramName] = param.value(paramVal);
30033           }
30034           for (/**/; i < nTotal; i++) {
30035             paramName = paramNames[i];
30036             values[paramName] = this.params[paramName].value(searchParams[paramName]);
30037           }
30038
30039           return values;
30040         };
30041
30042         /**
30043          * @ngdoc function
30044          * @name ui.router.util.type:UrlMatcher#parameters
30045          * @methodOf ui.router.util.type:UrlMatcher
30046          *
30047          * @description
30048          * Returns the names of all path and search parameters of this pattern in an unspecified order.
30049          *
30050          * @returns {Array.<string>}  An array of parameter names. Must be treated as read-only. If the
30051          *    pattern has no parameters, an empty array is returned.
30052          */
30053         UrlMatcher.prototype.parameters = function (param) {
30054           if (!isDefined(param)) return this.$$paramNames;
30055           return this.params[param] || null;
30056         };
30057
30058         /**
30059          * @ngdoc function
30060          * @name ui.router.util.type:UrlMatcher#validate
30061          * @methodOf ui.router.util.type:UrlMatcher
30062          *
30063          * @description
30064          * Checks an object hash of parameters to validate their correctness according to the parameter
30065          * types of this `UrlMatcher`.
30066          *
30067          * @param {Object} params The object hash of parameters to validate.
30068          * @returns {boolean} Returns `true` if `params` validates, otherwise `false`.
30069          */
30070         UrlMatcher.prototype.validates = function (params) {
30071           return this.params.$$validates(params);
30072         };
30073
30074         /**
30075          * @ngdoc function
30076          * @name ui.router.util.type:UrlMatcher#format
30077          * @methodOf ui.router.util.type:UrlMatcher
30078          *
30079          * @description
30080          * Creates a URL that matches this pattern by substituting the specified values
30081          * for the path and search parameters. Null values for path parameters are
30082          * treated as empty strings.
30083          *
30084          * @example
30085          * <pre>
30086          * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
30087          * // returns '/user/bob?q=yes'
30088          * </pre>
30089          *
30090          * @param {Object} values  the values to substitute for the parameters in this pattern.
30091          * @returns {string}  the formatted URL (path and optionally search part).
30092          */
30093         UrlMatcher.prototype.format = function (values) {
30094           values = values || {};
30095           var segments = this.segments, params = this.parameters(), paramset = this.params;
30096           if (!this.validates(values)) return null;
30097
30098           var i, search = false, nPath = segments.length - 1, nTotal = params.length, result = segments[0];
30099
30100           function encodeDashes(str) { // Replace dashes with encoded "\-"
30101             return encodeURIComponent(str).replace(/-/g, function(c) { return '%5C%' + c.charCodeAt(0).toString(16).toUpperCase(); });
30102           }
30103
30104           for (i = 0; i < nTotal; i++) {
30105             var isPathParam = i < nPath;
30106             var name = params[i], param = paramset[name], value = param.value(values[name]);
30107             var isDefaultValue = param.isOptional && param.type.equals(param.value(), value);
30108             var squash = isDefaultValue ? param.squash : false;
30109             var encoded = param.type.encode(value);
30110
30111             if (isPathParam) {
30112               var nextSegment = segments[i + 1];
30113               if (squash === false) {
30114                 if (encoded != null) {
30115                   if (isArray(encoded)) {
30116                     result += map(encoded, encodeDashes).join("-");
30117                   } else {
30118                     result += encodeURIComponent(encoded);
30119                   }
30120                 }
30121                 result += nextSegment;
30122               } else if (squash === true) {
30123                 var capture = result.match(/\/$/) ? /\/?(.*)/ : /(.*)/;
30124                 result += nextSegment.match(capture)[1];
30125               } else if (isString(squash)) {
30126                 result += squash + nextSegment;
30127               }
30128             } else {
30129               if (encoded == null || (isDefaultValue && squash !== false)) continue;
30130               if (!isArray(encoded)) encoded = [ encoded ];
30131               encoded = map(encoded, encodeURIComponent).join('&' + name + '=');
30132               result += (search ? '&' : '?') + (name + '=' + encoded);
30133               search = true;
30134             }
30135           }
30136
30137           return result;
30138         };
30139
30140         /**
30141          * @ngdoc object
30142          * @name ui.router.util.type:Type
30143          *
30144          * @description
30145          * Implements an interface to define custom parameter types that can be decoded from and encoded to
30146          * string parameters matched in a URL. Used by {@link ui.router.util.type:UrlMatcher `UrlMatcher`}
30147          * objects when matching or formatting URLs, or comparing or validating parameter values.
30148          *
30149          * See {@link ui.router.util.$urlMatcherFactory#methods_type `$urlMatcherFactory#type()`} for more
30150          * information on registering custom types.
30151          *
30152          * @param {Object} config  A configuration object which contains the custom type definition.  The object's
30153          *        properties will override the default methods and/or pattern in `Type`'s public interface.
30154          * @example
30155          * <pre>
30156          * {
30157          *   decode: function(val) { return parseInt(val, 10); },
30158          *   encode: function(val) { return val && val.toString(); },
30159          *   equals: function(a, b) { return this.is(a) && a === b; },
30160          *   is: function(val) { return angular.isNumber(val) isFinite(val) && val % 1 === 0; },
30161          *   pattern: /\d+/
30162          * }
30163          * </pre>
30164          *
30165          * @property {RegExp} pattern The regular expression pattern used to match values of this type when
30166          *           coming from a substring of a URL.
30167          *
30168          * @returns {Object}  Returns a new `Type` object.
30169          */
30170         function Type(config) {
30171           extend(this, config);
30172         }
30173
30174         /**
30175          * @ngdoc function
30176          * @name ui.router.util.type:Type#is
30177          * @methodOf ui.router.util.type:Type
30178          *
30179          * @description
30180          * Detects whether a value is of a particular type. Accepts a native (decoded) value
30181          * and determines whether it matches the current `Type` object.
30182          *
30183          * @param {*} val  The value to check.
30184          * @param {string} key  Optional. If the type check is happening in the context of a specific
30185          *        {@link ui.router.util.type:UrlMatcher `UrlMatcher`} object, this is the name of the
30186          *        parameter in which `val` is stored. Can be used for meta-programming of `Type` objects.
30187          * @returns {Boolean}  Returns `true` if the value matches the type, otherwise `false`.
30188          */
30189         Type.prototype.is = function(val, key) {
30190           return true;
30191         };
30192
30193         /**
30194          * @ngdoc function
30195          * @name ui.router.util.type:Type#encode
30196          * @methodOf ui.router.util.type:Type
30197          *
30198          * @description
30199          * Encodes a custom/native type value to a string that can be embedded in a URL. Note that the
30200          * return value does *not* need to be URL-safe (i.e. passed through `encodeURIComponent()`), it
30201          * only needs to be a representation of `val` that has been coerced to a string.
30202          *
30203          * @param {*} val  The value to encode.
30204          * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
30205          *        meta-programming of `Type` objects.
30206          * @returns {string}  Returns a string representation of `val` that can be encoded in a URL.
30207          */
30208         Type.prototype.encode = function(val, key) {
30209           return val;
30210         };
30211
30212         /**
30213          * @ngdoc function
30214          * @name ui.router.util.type:Type#decode
30215          * @methodOf ui.router.util.type:Type
30216          *
30217          * @description
30218          * Converts a parameter value (from URL string or transition param) to a custom/native value.
30219          *
30220          * @param {string} val  The URL parameter value to decode.
30221          * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
30222          *        meta-programming of `Type` objects.
30223          * @returns {*}  Returns a custom representation of the URL parameter value.
30224          */
30225         Type.prototype.decode = function(val, key) {
30226           return val;
30227         };
30228
30229         /**
30230          * @ngdoc function
30231          * @name ui.router.util.type:Type#equals
30232          * @methodOf ui.router.util.type:Type
30233          *
30234          * @description
30235          * Determines whether two decoded values are equivalent.
30236          *
30237          * @param {*} a  A value to compare against.
30238          * @param {*} b  A value to compare against.
30239          * @returns {Boolean}  Returns `true` if the values are equivalent/equal, otherwise `false`.
30240          */
30241         Type.prototype.equals = function(a, b) {
30242           return a == b;
30243         };
30244
30245         Type.prototype.$subPattern = function() {
30246           var sub = this.pattern.toString();
30247           return sub.substr(1, sub.length - 2);
30248         };
30249
30250         Type.prototype.pattern = /.*/;
30251
30252         Type.prototype.toString = function() { return "{Type:" + this.name + "}"; };
30253
30254         /** Given an encoded string, or a decoded object, returns a decoded object */
30255         Type.prototype.$normalize = function(val) {
30256           return this.is(val) ? val : this.decode(val);
30257         };
30258
30259         /*
30260          * Wraps an existing custom Type as an array of Type, depending on 'mode'.
30261          * e.g.:
30262          * - urlmatcher pattern "/path?{queryParam[]:int}"
30263          * - url: "/path?queryParam=1&queryParam=2
30264          * - $stateParams.queryParam will be [1, 2]
30265          * if `mode` is "auto", then
30266          * - url: "/path?queryParam=1 will create $stateParams.queryParam: 1
30267          * - url: "/path?queryParam=1&queryParam=2 will create $stateParams.queryParam: [1, 2]
30268          */
30269         Type.prototype.$asArray = function(mode, isSearch) {
30270           if (!mode) return this;
30271           if (mode === "auto" && !isSearch) throw new Error("'auto' array mode is for query parameters only");
30272
30273           function ArrayType(type, mode) {
30274             function bindTo(type, callbackName) {
30275               return function() {
30276                 return type[callbackName].apply(type, arguments);
30277               };
30278             }
30279
30280             // Wrap non-array value as array
30281             function arrayWrap(val) { return isArray(val) ? val : (isDefined(val) ? [ val ] : []); }
30282             // Unwrap array value for "auto" mode. Return undefined for empty array.
30283             function arrayUnwrap(val) {
30284               switch(val.length) {
30285                 case 0: return undefined;
30286                 case 1: return mode === "auto" ? val[0] : val;
30287                 default: return val;
30288               }
30289             }
30290             function falsey(val) { return !val; }
30291
30292             // Wraps type (.is/.encode/.decode) functions to operate on each value of an array
30293             function arrayHandler(callback, allTruthyMode) {
30294               return function handleArray(val) {
30295                 val = arrayWrap(val);
30296                 var result = map(val, callback);
30297                 if (allTruthyMode === true)
30298                   return filter(result, falsey).length === 0;
30299                 return arrayUnwrap(result);
30300               };
30301             }
30302
30303             // Wraps type (.equals) functions to operate on each value of an array
30304             function arrayEqualsHandler(callback) {
30305               return function handleArray(val1, val2) {
30306                 var left = arrayWrap(val1), right = arrayWrap(val2);
30307                 if (left.length !== right.length) return false;
30308                 for (var i = 0; i < left.length; i++) {
30309                   if (!callback(left[i], right[i])) return false;
30310                 }
30311                 return true;
30312               };
30313             }
30314
30315             this.encode = arrayHandler(bindTo(type, 'encode'));
30316             this.decode = arrayHandler(bindTo(type, 'decode'));
30317             this.is     = arrayHandler(bindTo(type, 'is'), true);
30318             this.equals = arrayEqualsHandler(bindTo(type, 'equals'));
30319             this.pattern = type.pattern;
30320             this.$normalize = arrayHandler(bindTo(type, '$normalize'));
30321             this.name = type.name;
30322             this.$arrayMode = mode;
30323           }
30324
30325           return new ArrayType(this, mode);
30326         };
30327
30328
30329
30330         /**
30331          * @ngdoc object
30332          * @name ui.router.util.$urlMatcherFactory
30333          *
30334          * @description
30335          * Factory for {@link ui.router.util.type:UrlMatcher `UrlMatcher`} instances. The factory
30336          * is also available to providers under the name `$urlMatcherFactoryProvider`.
30337          */
30338         function $UrlMatcherFactory() {
30339           $$UMFP = this;
30340
30341           var isCaseInsensitive = false, isStrictMode = true, defaultSquashPolicy = false;
30342
30343           function valToString(val) { return val != null ? val.toString().replace(/\//g, "%2F") : val; }
30344           function valFromString(val) { return val != null ? val.toString().replace(/%2F/g, "/") : val; }
30345
30346           var $types = {}, enqueue = true, typeQueue = [], injector, defaultTypes = {
30347             string: {
30348               encode: valToString,
30349               decode: valFromString,
30350               // TODO: in 1.0, make string .is() return false if value is undefined/null by default.
30351               // In 0.2.x, string params are optional by default for backwards compat
30352               is: function(val) { return val == null || !isDefined(val) || typeof val === "string"; },
30353               pattern: /[^/]*/
30354             },
30355             int: {
30356               encode: valToString,
30357               decode: function(val) { return parseInt(val, 10); },
30358               is: function(val) { return isDefined(val) && this.decode(val.toString()) === val; },
30359               pattern: /\d+/
30360             },
30361             bool: {
30362               encode: function(val) { return val ? 1 : 0; },
30363               decode: function(val) { return parseInt(val, 10) !== 0; },
30364               is: function(val) { return val === true || val === false; },
30365               pattern: /0|1/
30366             },
30367             date: {
30368               encode: function (val) {
30369                 if (!this.is(val))
30370                   return undefined;
30371                 return [ val.getFullYear(),
30372                   ('0' + (val.getMonth() + 1)).slice(-2),
30373                   ('0' + val.getDate()).slice(-2)
30374                 ].join("-");
30375               },
30376               decode: function (val) {
30377                 if (this.is(val)) return val;
30378                 var match = this.capture.exec(val);
30379                 return match ? new Date(match[1], match[2] - 1, match[3]) : undefined;
30380               },
30381               is: function(val) { return val instanceof Date && !isNaN(val.valueOf()); },
30382               equals: function (a, b) { return this.is(a) && this.is(b) && a.toISOString() === b.toISOString(); },
30383               pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/,
30384               capture: /([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/
30385             },
30386             json: {
30387               encode: angular.toJson,
30388               decode: angular.fromJson,
30389               is: angular.isObject,
30390               equals: angular.equals,
30391               pattern: /[^/]*/
30392             },
30393             any: { // does not encode/decode
30394               encode: angular.identity,
30395               decode: angular.identity,
30396               equals: angular.equals,
30397               pattern: /.*/
30398             }
30399           };
30400
30401           function getDefaultConfig() {
30402             return {
30403               strict: isStrictMode,
30404               caseInsensitive: isCaseInsensitive
30405             };
30406           }
30407
30408           function isInjectable(value) {
30409             return (isFunction(value) || (isArray(value) && isFunction(value[value.length - 1])));
30410           }
30411
30412           /**
30413            * [Internal] Get the default value of a parameter, which may be an injectable function.
30414            */
30415           $UrlMatcherFactory.$$getDefaultValue = function(config) {
30416             if (!isInjectable(config.value)) return config.value;
30417             if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
30418             return injector.invoke(config.value);
30419           };
30420
30421           /**
30422            * @ngdoc function
30423            * @name ui.router.util.$urlMatcherFactory#caseInsensitive
30424            * @methodOf ui.router.util.$urlMatcherFactory
30425            *
30426            * @description
30427            * Defines whether URL matching should be case sensitive (the default behavior), or not.
30428            *
30429            * @param {boolean} value `false` to match URL in a case sensitive manner; otherwise `true`;
30430            * @returns {boolean} the current value of caseInsensitive
30431            */
30432           this.caseInsensitive = function(value) {
30433             if (isDefined(value))
30434               isCaseInsensitive = value;
30435             return isCaseInsensitive;
30436           };
30437
30438           /**
30439            * @ngdoc function
30440            * @name ui.router.util.$urlMatcherFactory#strictMode
30441            * @methodOf ui.router.util.$urlMatcherFactory
30442            *
30443            * @description
30444            * Defines whether URLs should match trailing slashes, or not (the default behavior).
30445            *
30446            * @param {boolean=} value `false` to match trailing slashes in URLs, otherwise `true`.
30447            * @returns {boolean} the current value of strictMode
30448            */
30449           this.strictMode = function(value) {
30450             if (isDefined(value))
30451               isStrictMode = value;
30452             return isStrictMode;
30453           };
30454
30455           /**
30456            * @ngdoc function
30457            * @name ui.router.util.$urlMatcherFactory#defaultSquashPolicy
30458            * @methodOf ui.router.util.$urlMatcherFactory
30459            *
30460            * @description
30461            * Sets the default behavior when generating or matching URLs with default parameter values.
30462            *
30463            * @param {string} value A string that defines the default parameter URL squashing behavior.
30464            *    `nosquash`: When generating an href with a default parameter value, do not squash the parameter value from the URL
30465            *    `slash`: When generating an href with a default parameter value, squash (remove) the parameter value, and, if the
30466            *             parameter is surrounded by slashes, squash (remove) one slash from the URL
30467            *    any other string, e.g. "~": When generating an href with a default parameter value, squash (remove)
30468            *             the parameter value from the URL and replace it with this string.
30469            */
30470           this.defaultSquashPolicy = function(value) {
30471             if (!isDefined(value)) return defaultSquashPolicy;
30472             if (value !== true && value !== false && !isString(value))
30473               throw new Error("Invalid squash policy: " + value + ". Valid policies: false, true, arbitrary-string");
30474             defaultSquashPolicy = value;
30475             return value;
30476           };
30477
30478           /**
30479            * @ngdoc function
30480            * @name ui.router.util.$urlMatcherFactory#compile
30481            * @methodOf ui.router.util.$urlMatcherFactory
30482            *
30483            * @description
30484            * Creates a {@link ui.router.util.type:UrlMatcher `UrlMatcher`} for the specified pattern.
30485            *
30486            * @param {string} pattern  The URL pattern.
30487            * @param {Object} config  The config object hash.
30488            * @returns {UrlMatcher}  The UrlMatcher.
30489            */
30490           this.compile = function (pattern, config) {
30491             return new UrlMatcher(pattern, extend(getDefaultConfig(), config));
30492           };
30493
30494           /**
30495            * @ngdoc function
30496            * @name ui.router.util.$urlMatcherFactory#isMatcher
30497            * @methodOf ui.router.util.$urlMatcherFactory
30498            *
30499            * @description
30500            * Returns true if the specified object is a `UrlMatcher`, or false otherwise.
30501            *
30502            * @param {Object} object  The object to perform the type check against.
30503            * @returns {Boolean}  Returns `true` if the object matches the `UrlMatcher` interface, by
30504            *          implementing all the same methods.
30505            */
30506           this.isMatcher = function (o) {
30507             if (!isObject(o)) return false;
30508             var result = true;
30509
30510             forEach(UrlMatcher.prototype, function(val, name) {
30511               if (isFunction(val)) {
30512                 result = result && (isDefined(o[name]) && isFunction(o[name]));
30513               }
30514             });
30515             return result;
30516           };
30517
30518           /**
30519            * @ngdoc function
30520            * @name ui.router.util.$urlMatcherFactory#type
30521            * @methodOf ui.router.util.$urlMatcherFactory
30522            *
30523            * @description
30524            * Registers a custom {@link ui.router.util.type:Type `Type`} object that can be used to
30525            * generate URLs with typed parameters.
30526            *
30527            * @param {string} name  The type name.
30528            * @param {Object|Function} definition   The type definition. See
30529            *        {@link ui.router.util.type:Type `Type`} for information on the values accepted.
30530            * @param {Object|Function} definitionFn (optional) A function that is injected before the app
30531            *        runtime starts.  The result of this function is merged into the existing `definition`.
30532            *        See {@link ui.router.util.type:Type `Type`} for information on the values accepted.
30533            *
30534            * @returns {Object}  Returns `$urlMatcherFactoryProvider`.
30535            *
30536            * @example
30537            * This is a simple example of a custom type that encodes and decodes items from an
30538            * array, using the array index as the URL-encoded value:
30539            *
30540            * <pre>
30541            * var list = ['John', 'Paul', 'George', 'Ringo'];
30542            *
30543            * $urlMatcherFactoryProvider.type('listItem', {
30544            *   encode: function(item) {
30545            *     // Represent the list item in the URL using its corresponding index
30546            *     return list.indexOf(item);
30547            *   },
30548            *   decode: function(item) {
30549            *     // Look up the list item by index
30550            *     return list[parseInt(item, 10)];
30551            *   },
30552            *   is: function(item) {
30553            *     // Ensure the item is valid by checking to see that it appears
30554            *     // in the list
30555            *     return list.indexOf(item) > -1;
30556            *   }
30557            * });
30558            *
30559            * $stateProvider.state('list', {
30560            *   url: "/list/{item:listItem}",
30561            *   controller: function($scope, $stateParams) {
30562            *     console.log($stateParams.item);
30563            *   }
30564            * });
30565            *
30566            * // ...
30567            *
30568            * // Changes URL to '/list/3', logs "Ringo" to the console
30569            * $state.go('list', { item: "Ringo" });
30570            * </pre>
30571            *
30572            * This is a more complex example of a type that relies on dependency injection to
30573            * interact with services, and uses the parameter name from the URL to infer how to
30574            * handle encoding and decoding parameter values:
30575            *
30576            * <pre>
30577            * // Defines a custom type that gets a value from a service,
30578            * // where each service gets different types of values from
30579            * // a backend API:
30580            * $urlMatcherFactoryProvider.type('dbObject', {}, function(Users, Posts) {
30581            *
30582            *   // Matches up services to URL parameter names
30583            *   var services = {
30584            *     user: Users,
30585            *     post: Posts
30586            *   };
30587            *
30588            *   return {
30589            *     encode: function(object) {
30590            *       // Represent the object in the URL using its unique ID
30591            *       return object.id;
30592            *     },
30593            *     decode: function(value, key) {
30594            *       // Look up the object by ID, using the parameter
30595            *       // name (key) to call the correct service
30596            *       return services[key].findById(value);
30597            *     },
30598            *     is: function(object, key) {
30599            *       // Check that object is a valid dbObject
30600            *       return angular.isObject(object) && object.id && services[key];
30601            *     }
30602            *     equals: function(a, b) {
30603            *       // Check the equality of decoded objects by comparing
30604            *       // their unique IDs
30605            *       return a.id === b.id;
30606            *     }
30607            *   };
30608            * });
30609            *
30610            * // In a config() block, you can then attach URLs with
30611            * // type-annotated parameters:
30612            * $stateProvider.state('users', {
30613            *   url: "/users",
30614            *   // ...
30615            * }).state('users.item', {
30616            *   url: "/{user:dbObject}",
30617            *   controller: function($scope, $stateParams) {
30618            *     // $stateParams.user will now be an object returned from
30619            *     // the Users service
30620            *   },
30621            *   // ...
30622            * });
30623            * </pre>
30624            */
30625           this.type = function (name, definition, definitionFn) {
30626             if (!isDefined(definition)) return $types[name];
30627             if ($types.hasOwnProperty(name)) throw new Error("A type named '" + name + "' has already been defined.");
30628
30629             $types[name] = new Type(extend({ name: name }, definition));
30630             if (definitionFn) {
30631               typeQueue.push({ name: name, def: definitionFn });
30632               if (!enqueue) flushTypeQueue();
30633             }
30634             return this;
30635           };
30636
30637           // `flushTypeQueue()` waits until `$urlMatcherFactory` is injected before invoking the queued `definitionFn`s
30638           function flushTypeQueue() {
30639             while(typeQueue.length) {
30640               var type = typeQueue.shift();
30641               if (type.pattern) throw new Error("You cannot override a type's .pattern at runtime.");
30642               angular.extend($types[type.name], injector.invoke(type.def));
30643             }
30644           }
30645
30646           // Register default types. Store them in the prototype of $types.
30647           forEach(defaultTypes, function(type, name) { $types[name] = new Type(extend({name: name}, type)); });
30648           $types = inherit($types, {});
30649
30650           /* No need to document $get, since it returns this */
30651           this.$get = ['$injector', function ($injector) {
30652             injector = $injector;
30653             enqueue = false;
30654             flushTypeQueue();
30655
30656             forEach(defaultTypes, function(type, name) {
30657               if (!$types[name]) $types[name] = new Type(type);
30658             });
30659             return this;
30660           }];
30661
30662           this.Param = function Param(id, type, config, location) {
30663             var self = this;
30664             config = unwrapShorthand(config);
30665             type = getType(config, type, location);
30666             var arrayMode = getArrayMode();
30667             type = arrayMode ? type.$asArray(arrayMode, location === "search") : type;
30668             if (type.name === "string" && !arrayMode && location === "path" && config.value === undefined)
30669               config.value = ""; // for 0.2.x; in 0.3.0+ do not automatically default to ""
30670             var isOptional = config.value !== undefined;
30671             var squash = getSquashPolicy(config, isOptional);
30672             var replace = getReplace(config, arrayMode, isOptional, squash);
30673
30674             function unwrapShorthand(config) {
30675               var keys = isObject(config) ? objectKeys(config) : [];
30676               var isShorthand = indexOf(keys, "value") === -1 && indexOf(keys, "type") === -1 &&
30677                                 indexOf(keys, "squash") === -1 && indexOf(keys, "array") === -1;
30678               if (isShorthand) config = { value: config };
30679               config.$$fn = isInjectable(config.value) ? config.value : function () { return config.value; };
30680               return config;
30681             }
30682
30683             function getType(config, urlType, location) {
30684               if (config.type && urlType) throw new Error("Param '"+id+"' has two type configurations.");
30685               if (urlType) return urlType;
30686               if (!config.type) return (location === "config" ? $types.any : $types.string);
30687               return config.type instanceof Type ? config.type : new Type(config.type);
30688             }
30689
30690             // array config: param name (param[]) overrides default settings.  explicit config overrides param name.
30691             function getArrayMode() {
30692               var arrayDefaults = { array: (location === "search" ? "auto" : false) };
30693               var arrayParamNomenclature = id.match(/\[\]$/) ? { array: true } : {};
30694               return extend(arrayDefaults, arrayParamNomenclature, config).array;
30695             }
30696
30697             /**
30698              * returns false, true, or the squash value to indicate the "default parameter url squash policy".
30699              */
30700             function getSquashPolicy(config, isOptional) {
30701               var squash = config.squash;
30702               if (!isOptional || squash === false) return false;
30703               if (!isDefined(squash) || squash == null) return defaultSquashPolicy;
30704               if (squash === true || isString(squash)) return squash;
30705               throw new Error("Invalid squash policy: '" + squash + "'. Valid policies: false, true, or arbitrary string");
30706             }
30707
30708             function getReplace(config, arrayMode, isOptional, squash) {
30709               var replace, configuredKeys, defaultPolicy = [
30710                 { from: "",   to: (isOptional || arrayMode ? undefined : "") },
30711                 { from: null, to: (isOptional || arrayMode ? undefined : "") }
30712               ];
30713               replace = isArray(config.replace) ? config.replace : [];
30714               if (isString(squash))
30715                 replace.push({ from: squash, to: undefined });
30716               configuredKeys = map(replace, function(item) { return item.from; } );
30717               return filter(defaultPolicy, function(item) { return indexOf(configuredKeys, item.from) === -1; }).concat(replace);
30718             }
30719
30720             /**
30721              * [Internal] Get the default value of a parameter, which may be an injectable function.
30722              */
30723             function $$getDefaultValue() {
30724               if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
30725               var defaultValue = injector.invoke(config.$$fn);
30726               if (defaultValue !== null && defaultValue !== undefined && !self.type.is(defaultValue))
30727                 throw new Error("Default value (" + defaultValue + ") for parameter '" + self.id + "' is not an instance of Type (" + self.type.name + ")");
30728               return defaultValue;
30729             }
30730
30731             /**
30732              * [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the
30733              * default value, which may be the result of an injectable function.
30734              */
30735             function $value(value) {
30736               function hasReplaceVal(val) { return function(obj) { return obj.from === val; }; }
30737               function $replace(value) {
30738                 var replacement = map(filter(self.replace, hasReplaceVal(value)), function(obj) { return obj.to; });
30739                 return replacement.length ? replacement[0] : value;
30740               }
30741               value = $replace(value);
30742               return !isDefined(value) ? $$getDefaultValue() : self.type.$normalize(value);
30743             }
30744
30745             function toString() { return "{Param:" + id + " " + type + " squash: '" + squash + "' optional: " + isOptional + "}"; }
30746
30747             extend(this, {
30748               id: id,
30749               type: type,
30750               location: location,
30751               array: arrayMode,
30752               squash: squash,
30753               replace: replace,
30754               isOptional: isOptional,
30755               value: $value,
30756               dynamic: undefined,
30757               config: config,
30758               toString: toString
30759             });
30760           };
30761
30762           function ParamSet(params) {
30763             extend(this, params || {});
30764           }
30765
30766           ParamSet.prototype = {
30767             $$new: function() {
30768               return inherit(this, extend(new ParamSet(), { $$parent: this}));
30769             },
30770             $$keys: function () {
30771               var keys = [], chain = [], parent = this,
30772                 ignore = objectKeys(ParamSet.prototype);
30773               while (parent) { chain.push(parent); parent = parent.$$parent; }
30774               chain.reverse();
30775               forEach(chain, function(paramset) {
30776                 forEach(objectKeys(paramset), function(key) {
30777                     if (indexOf(keys, key) === -1 && indexOf(ignore, key) === -1) keys.push(key);
30778                 });
30779               });
30780               return keys;
30781             },
30782             $$values: function(paramValues) {
30783               var values = {}, self = this;
30784               forEach(self.$$keys(), function(key) {
30785                 values[key] = self[key].value(paramValues && paramValues[key]);
30786               });
30787               return values;
30788             },
30789             $$equals: function(paramValues1, paramValues2) {
30790               var equal = true, self = this;
30791               forEach(self.$$keys(), function(key) {
30792                 var left = paramValues1 && paramValues1[key], right = paramValues2 && paramValues2[key];
30793                 if (!self[key].type.equals(left, right)) equal = false;
30794               });
30795               return equal;
30796             },
30797             $$validates: function $$validate(paramValues) {
30798               var keys = this.$$keys(), i, param, rawVal, normalized, encoded;
30799               for (i = 0; i < keys.length; i++) {
30800                 param = this[keys[i]];
30801                 rawVal = paramValues[keys[i]];
30802                 if ((rawVal === undefined || rawVal === null) && param.isOptional)
30803                   break; // There was no parameter value, but the param is optional
30804                 normalized = param.type.$normalize(rawVal);
30805                 if (!param.type.is(normalized))
30806                   return false; // The value was not of the correct Type, and could not be decoded to the correct Type
30807                 encoded = param.type.encode(normalized);
30808                 if (angular.isString(encoded) && !param.type.pattern.exec(encoded))
30809                   return false; // The value was of the correct type, but when encoded, did not match the Type's regexp
30810               }
30811               return true;
30812             },
30813             $$parent: undefined
30814           };
30815
30816           this.ParamSet = ParamSet;
30817         }
30818
30819         // Register as a provider so it's available to other providers
30820         angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory);
30821         angular.module('ui.router.util').run(['$urlMatcherFactory', function($urlMatcherFactory) { }]);
30822
30823         /**
30824          * @ngdoc object
30825          * @name ui.router.router.$urlRouterProvider
30826          *
30827          * @requires ui.router.util.$urlMatcherFactoryProvider
30828          * @requires $locationProvider
30829          *
30830          * @description
30831          * `$urlRouterProvider` has the responsibility of watching `$location`. 
30832          * When `$location` changes it runs through a list of rules one by one until a 
30833          * match is found. `$urlRouterProvider` is used behind the scenes anytime you specify 
30834          * a url in a state configuration. All urls are compiled into a UrlMatcher object.
30835          *
30836          * There are several methods on `$urlRouterProvider` that make it useful to use directly
30837          * in your module config.
30838          */
30839         $UrlRouterProvider.$inject = ['$locationProvider', '$urlMatcherFactoryProvider'];
30840         function $UrlRouterProvider(   $locationProvider,   $urlMatcherFactory) {
30841           var rules = [], otherwise = null, interceptDeferred = false, listener;
30842
30843           // Returns a string that is a prefix of all strings matching the RegExp
30844           function regExpPrefix(re) {
30845             var prefix = /^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(re.source);
30846             return (prefix != null) ? prefix[1].replace(/\\(.)/g, "$1") : '';
30847           }
30848
30849           // Interpolates matched values into a String.replace()-style pattern
30850           function interpolate(pattern, match) {
30851             return pattern.replace(/\$(\$|\d{1,2})/, function (m, what) {
30852               return match[what === '$' ? 0 : Number(what)];
30853             });
30854           }
30855
30856           /**
30857            * @ngdoc function
30858            * @name ui.router.router.$urlRouterProvider#rule
30859            * @methodOf ui.router.router.$urlRouterProvider
30860            *
30861            * @description
30862            * Defines rules that are used by `$urlRouterProvider` to find matches for
30863            * specific URLs.
30864            *
30865            * @example
30866            * <pre>
30867            * var app = angular.module('app', ['ui.router.router']);
30868            *
30869            * app.config(function ($urlRouterProvider) {
30870            *   // Here's an example of how you might allow case insensitive urls
30871            *   $urlRouterProvider.rule(function ($injector, $location) {
30872            *     var path = $location.path(),
30873            *         normalized = path.toLowerCase();
30874            *
30875            *     if (path !== normalized) {
30876            *       return normalized;
30877            *     }
30878            *   });
30879            * });
30880            * </pre>
30881            *
30882            * @param {object} rule Handler function that takes `$injector` and `$location`
30883            * services as arguments. You can use them to return a valid path as a string.
30884            *
30885            * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance
30886            */
30887           this.rule = function (rule) {
30888             if (!isFunction(rule)) throw new Error("'rule' must be a function");
30889             rules.push(rule);
30890             return this;
30891           };
30892
30893           /**
30894            * @ngdoc object
30895            * @name ui.router.router.$urlRouterProvider#otherwise
30896            * @methodOf ui.router.router.$urlRouterProvider
30897            *
30898            * @description
30899            * Defines a path that is used when an invalid route is requested.
30900            *
30901            * @example
30902            * <pre>
30903            * var app = angular.module('app', ['ui.router.router']);
30904            *
30905            * app.config(function ($urlRouterProvider) {
30906            *   // if the path doesn't match any of the urls you configured
30907            *   // otherwise will take care of routing the user to the
30908            *   // specified url
30909            *   $urlRouterProvider.otherwise('/index');
30910            *
30911            *   // Example of using function rule as param
30912            *   $urlRouterProvider.otherwise(function ($injector, $location) {
30913            *     return '/a/valid/url';
30914            *   });
30915            * });
30916            * </pre>
30917            *
30918            * @param {string|object} rule The url path you want to redirect to or a function 
30919            * rule that returns the url path. The function version is passed two params: 
30920            * `$injector` and `$location` services, and must return a url string.
30921            *
30922            * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance
30923            */
30924           this.otherwise = function (rule) {
30925             if (isString(rule)) {
30926               var redirect = rule;
30927               rule = function () { return redirect; };
30928             }
30929             else if (!isFunction(rule)) throw new Error("'rule' must be a function");
30930             otherwise = rule;
30931             return this;
30932           };
30933
30934
30935           function handleIfMatch($injector, handler, match) {
30936             if (!match) return false;
30937             var result = $injector.invoke(handler, handler, { $match: match });
30938             return isDefined(result) ? result : true;
30939           }
30940
30941           /**
30942            * @ngdoc function
30943            * @name ui.router.router.$urlRouterProvider#when
30944            * @methodOf ui.router.router.$urlRouterProvider
30945            *
30946            * @description
30947            * Registers a handler for a given url matching. if handle is a string, it is
30948            * treated as a redirect, and is interpolated according to the syntax of match
30949            * (i.e. like `String.replace()` for `RegExp`, or like a `UrlMatcher` pattern otherwise).
30950            *
30951            * If the handler is a function, it is injectable. It gets invoked if `$location`
30952            * matches. You have the option of inject the match object as `$match`.
30953            *
30954            * The handler can return
30955            *
30956            * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter`
30957            *   will continue trying to find another one that matches.
30958            * - **string** which is treated as a redirect and passed to `$location.url()`
30959            * - **void** or any **truthy** value tells `$urlRouter` that the url was handled.
30960            *
30961            * @example
30962            * <pre>
30963            * var app = angular.module('app', ['ui.router.router']);
30964            *
30965            * app.config(function ($urlRouterProvider) {
30966            *   $urlRouterProvider.when($state.url, function ($match, $stateParams) {
30967            *     if ($state.$current.navigable !== state ||
30968            *         !equalForKeys($match, $stateParams) {
30969            *      $state.transitionTo(state, $match, false);
30970            *     }
30971            *   });
30972            * });
30973            * </pre>
30974            *
30975            * @param {string|object} what The incoming path that you want to redirect.
30976            * @param {string|object} handler The path you want to redirect your user to.
30977            */
30978           this.when = function (what, handler) {
30979             var redirect, handlerIsString = isString(handler);
30980             if (isString(what)) what = $urlMatcherFactory.compile(what);
30981
30982             if (!handlerIsString && !isFunction(handler) && !isArray(handler))
30983               throw new Error("invalid 'handler' in when()");
30984
30985             var strategies = {
30986               matcher: function (what, handler) {
30987                 if (handlerIsString) {
30988                   redirect = $urlMatcherFactory.compile(handler);
30989                   handler = ['$match', function ($match) { return redirect.format($match); }];
30990                 }
30991                 return extend(function ($injector, $location) {
30992                   return handleIfMatch($injector, handler, what.exec($location.path(), $location.search()));
30993                 }, {
30994                   prefix: isString(what.prefix) ? what.prefix : ''
30995                 });
30996               },
30997               regex: function (what, handler) {
30998                 if (what.global || what.sticky) throw new Error("when() RegExp must not be global or sticky");
30999
31000                 if (handlerIsString) {
31001                   redirect = handler;
31002                   handler = ['$match', function ($match) { return interpolate(redirect, $match); }];
31003                 }
31004                 return extend(function ($injector, $location) {
31005                   return handleIfMatch($injector, handler, what.exec($location.path()));
31006                 }, {
31007                   prefix: regExpPrefix(what)
31008                 });
31009               }
31010             };
31011
31012             var check = { matcher: $urlMatcherFactory.isMatcher(what), regex: what instanceof RegExp };
31013
31014             for (var n in check) {
31015               if (check[n]) return this.rule(strategies[n](what, handler));
31016             }
31017
31018             throw new Error("invalid 'what' in when()");
31019           };
31020
31021           /**
31022            * @ngdoc function
31023            * @name ui.router.router.$urlRouterProvider#deferIntercept
31024            * @methodOf ui.router.router.$urlRouterProvider
31025            *
31026            * @description
31027            * Disables (or enables) deferring location change interception.
31028            *
31029            * If you wish to customize the behavior of syncing the URL (for example, if you wish to
31030            * defer a transition but maintain the current URL), call this method at configuration time.
31031            * Then, at run time, call `$urlRouter.listen()` after you have configured your own
31032            * `$locationChangeSuccess` event handler.
31033            *
31034            * @example
31035            * <pre>
31036            * var app = angular.module('app', ['ui.router.router']);
31037            *
31038            * app.config(function ($urlRouterProvider) {
31039            *
31040            *   // Prevent $urlRouter from automatically intercepting URL changes;
31041            *   // this allows you to configure custom behavior in between
31042            *   // location changes and route synchronization:
31043            *   $urlRouterProvider.deferIntercept();
31044            *
31045            * }).run(function ($rootScope, $urlRouter, UserService) {
31046            *
31047            *   $rootScope.$on('$locationChangeSuccess', function(e) {
31048            *     // UserService is an example service for managing user state
31049            *     if (UserService.isLoggedIn()) return;
31050            *
31051            *     // Prevent $urlRouter's default handler from firing
31052            *     e.preventDefault();
31053            *
31054            *     UserService.handleLogin().then(function() {
31055            *       // Once the user has logged in, sync the current URL
31056            *       // to the router:
31057            *       $urlRouter.sync();
31058            *     });
31059            *   });
31060            *
31061            *   // Configures $urlRouter's listener *after* your custom listener
31062            *   $urlRouter.listen();
31063            * });
31064            * </pre>
31065            *
31066            * @param {boolean} defer Indicates whether to defer location change interception. Passing
31067                     no parameter is equivalent to `true`.
31068            */
31069           this.deferIntercept = function (defer) {
31070             if (defer === undefined) defer = true;
31071             interceptDeferred = defer;
31072           };
31073
31074           /**
31075            * @ngdoc object
31076            * @name ui.router.router.$urlRouter
31077            *
31078            * @requires $location
31079            * @requires $rootScope
31080            * @requires $injector
31081            * @requires $browser
31082            *
31083            * @description
31084            *
31085            */
31086           this.$get = $get;
31087           $get.$inject = ['$location', '$rootScope', '$injector', '$browser'];
31088           function $get(   $location,   $rootScope,   $injector,   $browser) {
31089
31090             var baseHref = $browser.baseHref(), location = $location.url(), lastPushedUrl;
31091
31092             function appendBasePath(url, isHtml5, absolute) {
31093               if (baseHref === '/') return url;
31094               if (isHtml5) return baseHref.slice(0, -1) + url;
31095               if (absolute) return baseHref.slice(1) + url;
31096               return url;
31097             }
31098
31099             // TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree
31100             function update(evt) {
31101               if (evt && evt.defaultPrevented) return;
31102               var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl;
31103               lastPushedUrl = undefined;
31104               // TODO: Re-implement this in 1.0 for https://github.com/angular-ui/ui-router/issues/1573
31105               //if (ignoreUpdate) return true;
31106
31107               function check(rule) {
31108                 var handled = rule($injector, $location);
31109
31110                 if (!handled) return false;
31111                 if (isString(handled)) $location.replace().url(handled);
31112                 return true;
31113               }
31114               var n = rules.length, i;
31115
31116               for (i = 0; i < n; i++) {
31117                 if (check(rules[i])) return;
31118               }
31119               // always check otherwise last to allow dynamic updates to the set of rules
31120               if (otherwise) check(otherwise);
31121             }
31122
31123             function listen() {
31124               listener = listener || $rootScope.$on('$locationChangeSuccess', update);
31125               return listener;
31126             }
31127
31128             if (!interceptDeferred) listen();
31129
31130             return {
31131               /**
31132                * @ngdoc function
31133                * @name ui.router.router.$urlRouter#sync
31134                * @methodOf ui.router.router.$urlRouter
31135                *
31136                * @description
31137                * Triggers an update; the same update that happens when the address bar url changes, aka `$locationChangeSuccess`.
31138                * This method is useful when you need to use `preventDefault()` on the `$locationChangeSuccess` event,
31139                * perform some custom logic (route protection, auth, config, redirection, etc) and then finally proceed
31140                * with the transition by calling `$urlRouter.sync()`.
31141                *
31142                * @example
31143                * <pre>
31144                * angular.module('app', ['ui.router'])
31145                *   .run(function($rootScope, $urlRouter) {
31146                *     $rootScope.$on('$locationChangeSuccess', function(evt) {
31147                *       // Halt state change from even starting
31148                *       evt.preventDefault();
31149                *       // Perform custom logic
31150                *       var meetsRequirement = ...
31151                *       // Continue with the update and state transition if logic allows
31152                *       if (meetsRequirement) $urlRouter.sync();
31153                *     });
31154                * });
31155                * </pre>
31156                */
31157               sync: function() {
31158                 update();
31159               },
31160
31161               listen: function() {
31162                 return listen();
31163               },
31164
31165               update: function(read) {
31166                 if (read) {
31167                   location = $location.url();
31168                   return;
31169                 }
31170                 if ($location.url() === location) return;
31171
31172                 $location.url(location);
31173                 $location.replace();
31174               },
31175
31176               push: function(urlMatcher, params, options) {
31177                  var url = urlMatcher.format(params || {});
31178
31179                 // Handle the special hash param, if needed
31180                 if (url !== null && params && params['#']) {
31181                     url += '#' + params['#'];
31182                 }
31183
31184                 $location.url(url);
31185                 lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined;
31186                 if (options && options.replace) $location.replace();
31187               },
31188
31189               /**
31190                * @ngdoc function
31191                * @name ui.router.router.$urlRouter#href
31192                * @methodOf ui.router.router.$urlRouter
31193                *
31194                * @description
31195                * A URL generation method that returns the compiled URL for a given
31196                * {@link ui.router.util.type:UrlMatcher `UrlMatcher`}, populated with the provided parameters.
31197                *
31198                * @example
31199                * <pre>
31200                * $bob = $urlRouter.href(new UrlMatcher("/about/:person"), {
31201                *   person: "bob"
31202                * });
31203                * // $bob == "/about/bob";
31204                * </pre>
31205                *
31206                * @param {UrlMatcher} urlMatcher The `UrlMatcher` object which is used as the template of the URL to generate.
31207                * @param {object=} params An object of parameter values to fill the matcher's required parameters.
31208                * @param {object=} options Options object. The options are:
31209                *
31210                * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
31211                *
31212                * @returns {string} Returns the fully compiled URL, or `null` if `params` fail validation against `urlMatcher`
31213                */
31214               href: function(urlMatcher, params, options) {
31215                 if (!urlMatcher.validates(params)) return null;
31216
31217                 var isHtml5 = $locationProvider.html5Mode();
31218                 if (angular.isObject(isHtml5)) {
31219                   isHtml5 = isHtml5.enabled;
31220                 }
31221                 
31222                 var url = urlMatcher.format(params);
31223                 options = options || {};
31224
31225                 if (!isHtml5 && url !== null) {
31226                   url = "#" + $locationProvider.hashPrefix() + url;
31227                 }
31228
31229                 // Handle special hash param, if needed
31230                 if (url !== null && params && params['#']) {
31231                   url += '#' + params['#'];
31232                 }
31233
31234                 url = appendBasePath(url, isHtml5, options.absolute);
31235
31236                 if (!options.absolute || !url) {
31237                   return url;
31238                 }
31239
31240                 var slash = (!isHtml5 && url ? '/' : ''), port = $location.port();
31241                 port = (port === 80 || port === 443 ? '' : ':' + port);
31242
31243                 return [$location.protocol(), '://', $location.host(), port, slash, url].join('');
31244               }
31245             };
31246           }
31247         }
31248
31249         angular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider);
31250
31251         /**
31252          * @ngdoc object
31253          * @name ui.router.state.$stateProvider
31254          *
31255          * @requires ui.router.router.$urlRouterProvider
31256          * @requires ui.router.util.$urlMatcherFactoryProvider
31257          *
31258          * @description
31259          * The new `$stateProvider` works similar to Angular's v1 router, but it focuses purely
31260          * on state.
31261          *
31262          * A state corresponds to a "place" in the application in terms of the overall UI and
31263          * navigation. A state describes (via the controller / template / view properties) what
31264          * the UI looks like and does at that place.
31265          *
31266          * States often have things in common, and the primary way of factoring out these
31267          * commonalities in this model is via the state hierarchy, i.e. parent/child states aka
31268          * nested states.
31269          *
31270          * The `$stateProvider` provides interfaces to declare these states for your app.
31271          */
31272         $StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];
31273         function $StateProvider(   $urlRouterProvider,   $urlMatcherFactory) {
31274
31275           var root, states = {}, $state, queue = {}, abstractKey = 'abstract';
31276
31277           // Builds state properties from definition passed to registerState()
31278           var stateBuilder = {
31279
31280             // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.
31281             // state.children = [];
31282             // if (parent) parent.children.push(state);
31283             parent: function(state) {
31284               if (isDefined(state.parent) && state.parent) return findState(state.parent);
31285               // regex matches any valid composite state name
31286               // would match "contact.list" but not "contacts"
31287               var compositeName = /^(.+)\.[^.]+$/.exec(state.name);
31288               return compositeName ? findState(compositeName[1]) : root;
31289             },
31290
31291             // inherit 'data' from parent and override by own values (if any)
31292             data: function(state) {
31293               if (state.parent && state.parent.data) {
31294                 state.data = state.self.data = extend({}, state.parent.data, state.data);
31295               }
31296               return state.data;
31297             },
31298
31299             // Build a URLMatcher if necessary, either via a relative or absolute URL
31300             url: function(state) {
31301               var url = state.url, config = { params: state.params || {} };
31302
31303               if (isString(url)) {
31304                 if (url.charAt(0) == '^') return $urlMatcherFactory.compile(url.substring(1), config);
31305                 return (state.parent.navigable || root).url.concat(url, config);
31306               }
31307
31308               if (!url || $urlMatcherFactory.isMatcher(url)) return url;
31309               throw new Error("Invalid url '" + url + "' in state '" + state + "'");
31310             },
31311
31312             // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
31313             navigable: function(state) {
31314               return state.url ? state : (state.parent ? state.parent.navigable : null);
31315             },
31316
31317             // Own parameters for this state. state.url.params is already built at this point. Create and add non-url params
31318             ownParams: function(state) {
31319               var params = state.url && state.url.params || new $$UMFP.ParamSet();
31320               forEach(state.params || {}, function(config, id) {
31321                 if (!params[id]) params[id] = new $$UMFP.Param(id, null, config, "config");
31322               });
31323               return params;
31324             },
31325
31326             // Derive parameters for this state and ensure they're a super-set of parent's parameters
31327             params: function(state) {
31328               return state.parent && state.parent.params ? extend(state.parent.params.$$new(), state.ownParams) : new $$UMFP.ParamSet();
31329             },
31330
31331             // If there is no explicit multi-view configuration, make one up so we don't have
31332             // to handle both cases in the view directive later. Note that having an explicit
31333             // 'views' property will mean the default unnamed view properties are ignored. This
31334             // is also a good time to resolve view names to absolute names, so everything is a
31335             // straight lookup at link time.
31336             views: function(state) {
31337               var views = {};
31338
31339               forEach(isDefined(state.views) ? state.views : { '': state }, function (view, name) {
31340                 if (name.indexOf('@') < 0) name += '@' + state.parent.name;
31341                 views[name] = view;
31342               });
31343               return views;
31344             },
31345
31346             // Keep a full path from the root down to this state as this is needed for state activation.
31347             path: function(state) {
31348               return state.parent ? state.parent.path.concat(state) : []; // exclude root from path
31349             },
31350
31351             // Speed up $state.contains() as it's used a lot
31352             includes: function(state) {
31353               var includes = state.parent ? extend({}, state.parent.includes) : {};
31354               includes[state.name] = true;
31355               return includes;
31356             },
31357
31358             $delegates: {}
31359           };
31360
31361           function isRelative(stateName) {
31362             return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0;
31363           }
31364
31365           function findState(stateOrName, base) {
31366             if (!stateOrName) return undefined;
31367
31368             var isStr = isString(stateOrName),
31369                 name  = isStr ? stateOrName : stateOrName.name,
31370                 path  = isRelative(name);
31371
31372             if (path) {
31373               if (!base) throw new Error("No reference point given for path '"  + name + "'");
31374               base = findState(base);
31375               
31376               var rel = name.split("."), i = 0, pathLength = rel.length, current = base;
31377
31378               for (; i < pathLength; i++) {
31379                 if (rel[i] === "" && i === 0) {
31380                   current = base;
31381                   continue;
31382                 }
31383                 if (rel[i] === "^") {
31384                   if (!current.parent) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'");
31385                   current = current.parent;
31386                   continue;
31387                 }
31388                 break;
31389               }
31390               rel = rel.slice(i).join(".");
31391               name = current.name + (current.name && rel ? "." : "") + rel;
31392             }
31393             var state = states[name];
31394
31395             if (state && (isStr || (!isStr && (state === stateOrName || state.self === stateOrName)))) {
31396               return state;
31397             }
31398             return undefined;
31399           }
31400
31401           function queueState(parentName, state) {
31402             if (!queue[parentName]) {
31403               queue[parentName] = [];
31404             }
31405             queue[parentName].push(state);
31406           }
31407
31408           function flushQueuedChildren(parentName) {
31409             var queued = queue[parentName] || [];
31410             while(queued.length) {
31411               registerState(queued.shift());
31412             }
31413           }
31414
31415           function registerState(state) {
31416             // Wrap a new object around the state so we can store our private details easily.
31417             state = inherit(state, {
31418               self: state,
31419               resolve: state.resolve || {},
31420               toString: function() { return this.name; }
31421             });
31422
31423             var name = state.name;
31424             if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name");
31425             if (states.hasOwnProperty(name)) throw new Error("State '" + name + "'' is already defined");
31426
31427             // Get parent name
31428             var parentName = (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.'))
31429                 : (isString(state.parent)) ? state.parent
31430                 : (isObject(state.parent) && isString(state.parent.name)) ? state.parent.name
31431                 : '';
31432
31433             // If parent is not registered yet, add state to queue and register later
31434             if (parentName && !states[parentName]) {
31435               return queueState(parentName, state.self);
31436             }
31437
31438             for (var key in stateBuilder) {
31439               if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]);
31440             }
31441             states[name] = state;
31442
31443             // Register the state in the global state list and with $urlRouter if necessary.
31444             if (!state[abstractKey] && state.url) {
31445               $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
31446                 if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
31447                   $state.transitionTo(state, $match, { inherit: true, location: false });
31448                 }
31449               }]);
31450             }
31451
31452             // Register any queued children
31453             flushQueuedChildren(name);
31454
31455             return state;
31456           }
31457
31458           // Checks text to see if it looks like a glob.
31459           function isGlob (text) {
31460             return text.indexOf('*') > -1;
31461           }
31462
31463           // Returns true if glob matches current $state name.
31464           function doesStateMatchGlob (glob) {
31465             var globSegments = glob.split('.'),
31466                 segments = $state.$current.name.split('.');
31467
31468             //match single stars
31469             for (var i = 0, l = globSegments.length; i < l; i++) {
31470               if (globSegments[i] === '*') {
31471                 segments[i] = '*';
31472               }
31473             }
31474
31475             //match greedy starts
31476             if (globSegments[0] === '**') {
31477                segments = segments.slice(indexOf(segments, globSegments[1]));
31478                segments.unshift('**');
31479             }
31480             //match greedy ends
31481             if (globSegments[globSegments.length - 1] === '**') {
31482                segments.splice(indexOf(segments, globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE);
31483                segments.push('**');
31484             }
31485
31486             if (globSegments.length != segments.length) {
31487               return false;
31488             }
31489
31490             return segments.join('') === globSegments.join('');
31491           }
31492
31493
31494           // Implicit root state that is always active
31495           root = registerState({
31496             name: '',
31497             url: '^',
31498             views: null,
31499             'abstract': true
31500           });
31501           root.navigable = null;
31502
31503
31504           /**
31505            * @ngdoc function
31506            * @name ui.router.state.$stateProvider#decorator
31507            * @methodOf ui.router.state.$stateProvider
31508            *
31509            * @description
31510            * Allows you to extend (carefully) or override (at your own peril) the 
31511            * `stateBuilder` object used internally by `$stateProvider`. This can be used 
31512            * to add custom functionality to ui-router, for example inferring templateUrl 
31513            * based on the state name.
31514            *
31515            * When passing only a name, it returns the current (original or decorated) builder
31516            * function that matches `name`.
31517            *
31518            * The builder functions that can be decorated are listed below. Though not all
31519            * necessarily have a good use case for decoration, that is up to you to decide.
31520            *
31521            * In addition, users can attach custom decorators, which will generate new 
31522            * properties within the state's internal definition. There is currently no clear 
31523            * use-case for this beyond accessing internal states (i.e. $state.$current), 
31524            * however, expect this to become increasingly relevant as we introduce additional 
31525            * meta-programming features.
31526            *
31527            * **Warning**: Decorators should not be interdependent because the order of 
31528            * execution of the builder functions in non-deterministic. Builder functions 
31529            * should only be dependent on the state definition object and super function.
31530            *
31531            *
31532            * Existing builder functions and current return values:
31533            *
31534            * - **parent** `{object}` - returns the parent state object.
31535            * - **data** `{object}` - returns state data, including any inherited data that is not
31536            *   overridden by own values (if any).
31537            * - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher}
31538            *   or `null`.
31539            * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is 
31540            *   navigable).
31541            * - **params** `{object}` - returns an array of state params that are ensured to 
31542            *   be a super-set of parent's params.
31543            * - **views** `{object}` - returns a views object where each key is an absolute view 
31544            *   name (i.e. "viewName@stateName") and each value is the config object 
31545            *   (template, controller) for the view. Even when you don't use the views object 
31546            *   explicitly on a state config, one is still created for you internally.
31547            *   So by decorating this builder function you have access to decorating template 
31548            *   and controller properties.
31549            * - **ownParams** `{object}` - returns an array of params that belong to the state, 
31550            *   not including any params defined by ancestor states.
31551            * - **path** `{string}` - returns the full path from the root down to this state. 
31552            *   Needed for state activation.
31553            * - **includes** `{object}` - returns an object that includes every state that 
31554            *   would pass a `$state.includes()` test.
31555            *
31556            * @example
31557            * <pre>
31558            * // Override the internal 'views' builder with a function that takes the state
31559            * // definition, and a reference to the internal function being overridden:
31560            * $stateProvider.decorator('views', function (state, parent) {
31561            *   var result = {},
31562            *       views = parent(state);
31563            *
31564            *   angular.forEach(views, function (config, name) {
31565            *     var autoName = (state.name + '.' + name).replace('.', '/');
31566            *     config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';
31567            *     result[name] = config;
31568            *   });
31569            *   return result;
31570            * });
31571            *
31572            * $stateProvider.state('home', {
31573            *   views: {
31574            *     'contact.list': { controller: 'ListController' },
31575            *     'contact.item': { controller: 'ItemController' }
31576            *   }
31577            * });
31578            *
31579            * // ...
31580            *
31581            * $state.go('home');
31582            * // Auto-populates list and item views with /partials/home/contact/list.html,
31583            * // and /partials/home/contact/item.html, respectively.
31584            * </pre>
31585            *
31586            * @param {string} name The name of the builder function to decorate. 
31587            * @param {object} func A function that is responsible for decorating the original 
31588            * builder function. The function receives two parameters:
31589            *
31590            *   - `{object}` - state - The state config object.
31591            *   - `{object}` - super - The original builder function.
31592            *
31593            * @return {object} $stateProvider - $stateProvider instance
31594            */
31595           this.decorator = decorator;
31596           function decorator(name, func) {
31597             /*jshint validthis: true */
31598             if (isString(name) && !isDefined(func)) {
31599               return stateBuilder[name];
31600             }
31601             if (!isFunction(func) || !isString(name)) {
31602               return this;
31603             }
31604             if (stateBuilder[name] && !stateBuilder.$delegates[name]) {
31605               stateBuilder.$delegates[name] = stateBuilder[name];
31606             }
31607             stateBuilder[name] = func;
31608             return this;
31609           }
31610
31611           /**
31612            * @ngdoc function
31613            * @name ui.router.state.$stateProvider#state
31614            * @methodOf ui.router.state.$stateProvider
31615            *
31616            * @description
31617            * Registers a state configuration under a given state name. The stateConfig object
31618            * has the following acceptable properties.
31619            *
31620            * @param {string} name A unique state name, e.g. "home", "about", "contacts".
31621            * To create a parent/child state use a dot, e.g. "about.sales", "home.newest".
31622            * @param {object} stateConfig State configuration object.
31623            * @param {string|function=} stateConfig.template
31624            * <a id='template'></a>
31625            *   html template as a string or a function that returns
31626            *   an html template as a string which should be used by the uiView directives. This property 
31627            *   takes precedence over templateUrl.
31628            *   
31629            *   If `template` is a function, it will be called with the following parameters:
31630            *
31631            *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by
31632            *     applying the current state
31633            *
31634            * <pre>template:
31635            *   "<h1>inline template definition</h1>" +
31636            *   "<div ui-view></div>"</pre>
31637            * <pre>template: function(params) {
31638            *       return "<h1>generated template</h1>"; }</pre>
31639            * </div>
31640            *
31641            * @param {string|function=} stateConfig.templateUrl
31642            * <a id='templateUrl'></a>
31643            *
31644            *   path or function that returns a path to an html
31645            *   template that should be used by uiView.
31646            *   
31647            *   If `templateUrl` is a function, it will be called with the following parameters:
31648            *
31649            *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by 
31650            *     applying the current state
31651            *
31652            * <pre>templateUrl: "home.html"</pre>
31653            * <pre>templateUrl: function(params) {
31654            *     return myTemplates[params.pageId]; }</pre>
31655            *
31656            * @param {function=} stateConfig.templateProvider
31657            * <a id='templateProvider'></a>
31658            *    Provider function that returns HTML content string.
31659            * <pre> templateProvider:
31660            *       function(MyTemplateService, params) {
31661            *         return MyTemplateService.getTemplate(params.pageId);
31662            *       }</pre>
31663            *
31664            * @param {string|function=} stateConfig.controller
31665            * <a id='controller'></a>
31666            *
31667            *  Controller fn that should be associated with newly
31668            *   related scope or the name of a registered controller if passed as a string.
31669            *   Optionally, the ControllerAs may be declared here.
31670            * <pre>controller: "MyRegisteredController"</pre>
31671            * <pre>controller:
31672            *     "MyRegisteredController as fooCtrl"}</pre>
31673            * <pre>controller: function($scope, MyService) {
31674            *     $scope.data = MyService.getData(); }</pre>
31675            *
31676            * @param {function=} stateConfig.controllerProvider
31677            * <a id='controllerProvider'></a>
31678            *
31679            * Injectable provider function that returns the actual controller or string.
31680            * <pre>controllerProvider:
31681            *   function(MyResolveData) {
31682            *     if (MyResolveData.foo)
31683            *       return "FooCtrl"
31684            *     else if (MyResolveData.bar)
31685            *       return "BarCtrl";
31686            *     else return function($scope) {
31687            *       $scope.baz = "Qux";
31688            *     }
31689            *   }</pre>
31690            *
31691            * @param {string=} stateConfig.controllerAs
31692            * <a id='controllerAs'></a>
31693            * 
31694            * A controller alias name. If present the controller will be
31695            *   published to scope under the controllerAs name.
31696            * <pre>controllerAs: "myCtrl"</pre>
31697            *
31698            * @param {string|object=} stateConfig.parent
31699            * <a id='parent'></a>
31700            * Optionally specifies the parent state of this state.
31701            *
31702            * <pre>parent: 'parentState'</pre>
31703            * <pre>parent: parentState // JS variable</pre>
31704            *
31705            * @param {object=} stateConfig.resolve
31706            * <a id='resolve'></a>
31707            *
31708            * An optional map&lt;string, function&gt; of dependencies which
31709            *   should be injected into the controller. If any of these dependencies are promises, 
31710            *   the router will wait for them all to be resolved before the controller is instantiated.
31711            *   If all the promises are resolved successfully, the $stateChangeSuccess event is fired
31712            *   and the values of the resolved promises are injected into any controllers that reference them.
31713            *   If any  of the promises are rejected the $stateChangeError event is fired.
31714            *
31715            *   The map object is:
31716            *   
31717            *   - key - {string}: name of dependency to be injected into controller
31718            *   - factory - {string|function}: If string then it is alias for service. Otherwise if function, 
31719            *     it is injected and return value it treated as dependency. If result is a promise, it is 
31720            *     resolved before its value is injected into controller.
31721            *
31722            * <pre>resolve: {
31723            *     myResolve1:
31724            *       function($http, $stateParams) {
31725            *         return $http.get("/api/foos/"+stateParams.fooID);
31726            *       }
31727            *     }</pre>
31728            *
31729            * @param {string=} stateConfig.url
31730            * <a id='url'></a>
31731            *
31732            *   A url fragment with optional parameters. When a state is navigated or
31733            *   transitioned to, the `$stateParams` service will be populated with any 
31734            *   parameters that were passed.
31735            *
31736            *   (See {@link ui.router.util.type:UrlMatcher UrlMatcher} `UrlMatcher`} for
31737            *   more details on acceptable patterns )
31738            *
31739            * examples:
31740            * <pre>url: "/home"
31741            * url: "/users/:userid"
31742            * url: "/books/{bookid:[a-zA-Z_-]}"
31743            * url: "/books/{categoryid:int}"
31744            * url: "/books/{publishername:string}/{categoryid:int}"
31745            * url: "/messages?before&after"
31746            * url: "/messages?{before:date}&{after:date}"
31747            * url: "/messages/:mailboxid?{before:date}&{after:date}"
31748            * </pre>
31749            *
31750            * @param {object=} stateConfig.views
31751            * <a id='views'></a>
31752            * an optional map&lt;string, object&gt; which defined multiple views, or targets views
31753            * manually/explicitly.
31754            *
31755            * Examples:
31756            *
31757            * Targets three named `ui-view`s in the parent state's template
31758            * <pre>views: {
31759            *     header: {
31760            *       controller: "headerCtrl",
31761            *       templateUrl: "header.html"
31762            *     }, body: {
31763            *       controller: "bodyCtrl",
31764            *       templateUrl: "body.html"
31765            *     }, footer: {
31766            *       controller: "footCtrl",
31767            *       templateUrl: "footer.html"
31768            *     }
31769            *   }</pre>
31770            *
31771            * Targets named `ui-view="header"` from grandparent state 'top''s template, and named `ui-view="body" from parent state's template.
31772            * <pre>views: {
31773            *     'header@top': {
31774            *       controller: "msgHeaderCtrl",
31775            *       templateUrl: "msgHeader.html"
31776            *     }, 'body': {
31777            *       controller: "messagesCtrl",
31778            *       templateUrl: "messages.html"
31779            *     }
31780            *   }</pre>
31781            *
31782            * @param {boolean=} [stateConfig.abstract=false]
31783            * <a id='abstract'></a>
31784            * An abstract state will never be directly activated,
31785            *   but can provide inherited properties to its common children states.
31786            * <pre>abstract: true</pre>
31787            *
31788            * @param {function=} stateConfig.onEnter
31789            * <a id='onEnter'></a>
31790            *
31791            * Callback function for when a state is entered. Good way
31792            *   to trigger an action or dispatch an event, such as opening a dialog.
31793            * If minifying your scripts, make sure to explictly annotate this function,
31794            * because it won't be automatically annotated by your build tools.
31795            *
31796            * <pre>onEnter: function(MyService, $stateParams) {
31797            *     MyService.foo($stateParams.myParam);
31798            * }</pre>
31799            *
31800            * @param {function=} stateConfig.onExit
31801            * <a id='onExit'></a>
31802            *
31803            * Callback function for when a state is exited. Good way to
31804            *   trigger an action or dispatch an event, such as opening a dialog.
31805            * If minifying your scripts, make sure to explictly annotate this function,
31806            * because it won't be automatically annotated by your build tools.
31807            *
31808            * <pre>onExit: function(MyService, $stateParams) {
31809            *     MyService.cleanup($stateParams.myParam);
31810            * }</pre>
31811            *
31812            * @param {boolean=} [stateConfig.reloadOnSearch=true]
31813            * <a id='reloadOnSearch'></a>
31814            *
31815            * If `false`, will not retrigger the same state
31816            *   just because a search/query parameter has changed (via $location.search() or $location.hash()). 
31817            *   Useful for when you'd like to modify $location.search() without triggering a reload.
31818            * <pre>reloadOnSearch: false</pre>
31819            *
31820            * @param {object=} stateConfig.data
31821            * <a id='data'></a>
31822            *
31823            * Arbitrary data object, useful for custom configuration.  The parent state's `data` is
31824            *   prototypally inherited.  In other words, adding a data property to a state adds it to
31825            *   the entire subtree via prototypal inheritance.
31826            *
31827            * <pre>data: {
31828            *     requiredRole: 'foo'
31829            * } </pre>
31830            *
31831            * @param {object=} stateConfig.params
31832            * <a id='params'></a>
31833            *
31834            * A map which optionally configures parameters declared in the `url`, or
31835            *   defines additional non-url parameters.  For each parameter being
31836            *   configured, add a configuration object keyed to the name of the parameter.
31837            *
31838            *   Each parameter configuration object may contain the following properties:
31839            *
31840            *   - ** value ** - {object|function=}: specifies the default value for this
31841            *     parameter.  This implicitly sets this parameter as optional.
31842            *
31843            *     When UI-Router routes to a state and no value is
31844            *     specified for this parameter in the URL or transition, the
31845            *     default value will be used instead.  If `value` is a function,
31846            *     it will be injected and invoked, and the return value used.
31847            *
31848            *     *Note*: `undefined` is treated as "no default value" while `null`
31849            *     is treated as "the default value is `null`".
31850            *
31851            *     *Shorthand*: If you only need to configure the default value of the
31852            *     parameter, you may use a shorthand syntax.   In the **`params`**
31853            *     map, instead mapping the param name to a full parameter configuration
31854            *     object, simply set map it to the default parameter value, e.g.:
31855            *
31856            * <pre>// define a parameter's default value
31857            * params: {
31858            *     param1: { value: "defaultValue" }
31859            * }
31860            * // shorthand default values
31861            * params: {
31862            *     param1: "defaultValue",
31863            *     param2: "param2Default"
31864            * }</pre>
31865            *
31866            *   - ** array ** - {boolean=}: *(default: false)* If true, the param value will be
31867            *     treated as an array of values.  If you specified a Type, the value will be
31868            *     treated as an array of the specified Type.  Note: query parameter values
31869            *     default to a special `"auto"` mode.
31870            *
31871            *     For query parameters in `"auto"` mode, if multiple  values for a single parameter
31872            *     are present in the URL (e.g.: `/foo?bar=1&bar=2&bar=3`) then the values
31873            *     are mapped to an array (e.g.: `{ foo: [ '1', '2', '3' ] }`).  However, if
31874            *     only one value is present (e.g.: `/foo?bar=1`) then the value is treated as single
31875            *     value (e.g.: `{ foo: '1' }`).
31876            *
31877            * <pre>params: {
31878            *     param1: { array: true }
31879            * }</pre>
31880            *
31881            *   - ** squash ** - {bool|string=}: `squash` configures how a default parameter value is represented in the URL when
31882            *     the current parameter value is the same as the default value. If `squash` is not set, it uses the
31883            *     configured default squash policy.
31884            *     (See {@link ui.router.util.$urlMatcherFactory#methods_defaultSquashPolicy `defaultSquashPolicy()`})
31885            *
31886            *   There are three squash settings:
31887            *
31888            *     - false: The parameter's default value is not squashed.  It is encoded and included in the URL
31889            *     - true: The parameter's default value is omitted from the URL.  If the parameter is preceeded and followed
31890            *       by slashes in the state's `url` declaration, then one of those slashes are omitted.
31891            *       This can allow for cleaner looking URLs.
31892            *     - `"<arbitrary string>"`: The parameter's default value is replaced with an arbitrary placeholder of  your choice.
31893            *
31894            * <pre>params: {
31895            *     param1: {
31896            *       value: "defaultId",
31897            *       squash: true
31898            * } }
31899            * // squash "defaultValue" to "~"
31900            * params: {
31901            *     param1: {
31902            *       value: "defaultValue",
31903            *       squash: "~"
31904            * } }
31905            * </pre>
31906            *
31907            *
31908            * @example
31909            * <pre>
31910            * // Some state name examples
31911            *
31912            * // stateName can be a single top-level name (must be unique).
31913            * $stateProvider.state("home", {});
31914            *
31915            * // Or it can be a nested state name. This state is a child of the
31916            * // above "home" state.
31917            * $stateProvider.state("home.newest", {});
31918            *
31919            * // Nest states as deeply as needed.
31920            * $stateProvider.state("home.newest.abc.xyz.inception", {});
31921            *
31922            * // state() returns $stateProvider, so you can chain state declarations.
31923            * $stateProvider
31924            *   .state("home", {})
31925            *   .state("about", {})
31926            *   .state("contacts", {});
31927            * </pre>
31928            *
31929            */
31930           this.state = state;
31931           function state(name, definition) {
31932             /*jshint validthis: true */
31933             if (isObject(name)) definition = name;
31934             else definition.name = name;
31935             registerState(definition);
31936             return this;
31937           }
31938
31939           /**
31940            * @ngdoc object
31941            * @name ui.router.state.$state
31942            *
31943            * @requires $rootScope
31944            * @requires $q
31945            * @requires ui.router.state.$view
31946            * @requires $injector
31947            * @requires ui.router.util.$resolve
31948            * @requires ui.router.state.$stateParams
31949            * @requires ui.router.router.$urlRouter
31950            *
31951            * @property {object} params A param object, e.g. {sectionId: section.id)}, that 
31952            * you'd like to test against the current active state.
31953            * @property {object} current A reference to the state's config object. However 
31954            * you passed it in. Useful for accessing custom data.
31955            * @property {object} transition Currently pending transition. A promise that'll 
31956            * resolve or reject.
31957            *
31958            * @description
31959            * `$state` service is responsible for representing states as well as transitioning
31960            * between them. It also provides interfaces to ask for current state or even states
31961            * you're coming from.
31962            */
31963           this.$get = $get;
31964           $get.$inject = ['$rootScope', '$q', '$view', '$injector', '$resolve', '$stateParams', '$urlRouter', '$location', '$urlMatcherFactory'];
31965           function $get(   $rootScope,   $q,   $view,   $injector,   $resolve,   $stateParams,   $urlRouter,   $location,   $urlMatcherFactory) {
31966
31967             var TransitionSuperseded = $q.reject(new Error('transition superseded'));
31968             var TransitionPrevented = $q.reject(new Error('transition prevented'));
31969             var TransitionAborted = $q.reject(new Error('transition aborted'));
31970             var TransitionFailed = $q.reject(new Error('transition failed'));
31971
31972             // Handles the case where a state which is the target of a transition is not found, and the user
31973             // can optionally retry or defer the transition
31974             function handleRedirect(redirect, state, params, options) {
31975               /**
31976                * @ngdoc event
31977                * @name ui.router.state.$state#$stateNotFound
31978                * @eventOf ui.router.state.$state
31979                * @eventType broadcast on root scope
31980                * @description
31981                * Fired when a requested state **cannot be found** using the provided state name during transition.
31982                * The event is broadcast allowing any handlers a single chance to deal with the error (usually by
31983                * lazy-loading the unfound state). A special `unfoundState` object is passed to the listener handler,
31984                * you can see its three properties in the example. You can use `event.preventDefault()` to abort the
31985                * transition and the promise returned from `go` will be rejected with a `'transition aborted'` value.
31986                *
31987                * @param {Object} event Event object.
31988                * @param {Object} unfoundState Unfound State information. Contains: `to, toParams, options` properties.
31989                * @param {State} fromState Current state object.
31990                * @param {Object} fromParams Current state params.
31991                *
31992                * @example
31993                *
31994                * <pre>
31995                * // somewhere, assume lazy.state has not been defined
31996                * $state.go("lazy.state", {a:1, b:2}, {inherit:false});
31997                *
31998                * // somewhere else
31999                * $scope.$on('$stateNotFound',
32000                * function(event, unfoundState, fromState, fromParams){
32001                *     console.log(unfoundState.to); // "lazy.state"
32002                *     console.log(unfoundState.toParams); // {a:1, b:2}
32003                *     console.log(unfoundState.options); // {inherit:false} + default options
32004                * })
32005                * </pre>
32006                */
32007               var evt = $rootScope.$broadcast('$stateNotFound', redirect, state, params);
32008
32009               if (evt.defaultPrevented) {
32010                 $urlRouter.update();
32011                 return TransitionAborted;
32012               }
32013
32014               if (!evt.retry) {
32015                 return null;
32016               }
32017
32018               // Allow the handler to return a promise to defer state lookup retry
32019               if (options.$retry) {
32020                 $urlRouter.update();
32021                 return TransitionFailed;
32022               }
32023               var retryTransition = $state.transition = $q.when(evt.retry);
32024
32025               retryTransition.then(function() {
32026                 if (retryTransition !== $state.transition) return TransitionSuperseded;
32027                 redirect.options.$retry = true;
32028                 return $state.transitionTo(redirect.to, redirect.toParams, redirect.options);
32029               }, function() {
32030                 return TransitionAborted;
32031               });
32032               $urlRouter.update();
32033
32034               return retryTransition;
32035             }
32036
32037             root.locals = { resolve: null, globals: { $stateParams: {} } };
32038
32039             $state = {
32040               params: {},
32041               current: root.self,
32042               $current: root,
32043               transition: null
32044             };
32045
32046             /**
32047              * @ngdoc function
32048              * @name ui.router.state.$state#reload
32049              * @methodOf ui.router.state.$state
32050              *
32051              * @description
32052              * A method that force reloads the current state. All resolves are re-resolved,
32053              * controllers reinstantiated, and events re-fired.
32054              *
32055              * @example
32056              * <pre>
32057              * var app angular.module('app', ['ui.router']);
32058              *
32059              * app.controller('ctrl', function ($scope, $state) {
32060              *   $scope.reload = function(){
32061              *     $state.reload();
32062              *   }
32063              * });
32064              * </pre>
32065              *
32066              * `reload()` is just an alias for:
32067              * <pre>
32068              * $state.transitionTo($state.current, $stateParams, { 
32069              *   reload: true, inherit: false, notify: true
32070              * });
32071              * </pre>
32072              *
32073              * @param {string=|object=} state - A state name or a state object, which is the root of the resolves to be re-resolved.
32074              * @example
32075              * <pre>
32076              * //assuming app application consists of 3 states: 'contacts', 'contacts.detail', 'contacts.detail.item' 
32077              * //and current state is 'contacts.detail.item'
32078              * var app angular.module('app', ['ui.router']);
32079              *
32080              * app.controller('ctrl', function ($scope, $state) {
32081              *   $scope.reload = function(){
32082              *     //will reload 'contact.detail' and 'contact.detail.item' states
32083              *     $state.reload('contact.detail');
32084              *   }
32085              * });
32086              * </pre>
32087              *
32088              * `reload()` is just an alias for:
32089              * <pre>
32090              * $state.transitionTo($state.current, $stateParams, { 
32091              *   reload: true, inherit: false, notify: true
32092              * });
32093              * </pre>
32094
32095              * @returns {promise} A promise representing the state of the new transition. See
32096              * {@link ui.router.state.$state#methods_go $state.go}.
32097              */
32098             $state.reload = function reload(state) {
32099               return $state.transitionTo($state.current, $stateParams, { reload: state || true, inherit: false, notify: true});
32100             };
32101
32102             /**
32103              * @ngdoc function
32104              * @name ui.router.state.$state#go
32105              * @methodOf ui.router.state.$state
32106              *
32107              * @description
32108              * Convenience method for transitioning to a new state. `$state.go` calls 
32109              * `$state.transitionTo` internally but automatically sets options to 
32110              * `{ location: true, inherit: true, relative: $state.$current, notify: true }`. 
32111              * This allows you to easily use an absolute or relative to path and specify 
32112              * only the parameters you'd like to update (while letting unspecified parameters 
32113              * inherit from the currently active ancestor states).
32114              *
32115              * @example
32116              * <pre>
32117              * var app = angular.module('app', ['ui.router']);
32118              *
32119              * app.controller('ctrl', function ($scope, $state) {
32120              *   $scope.changeState = function () {
32121              *     $state.go('contact.detail');
32122              *   };
32123              * });
32124              * </pre>
32125              * <img src='../ngdoc_assets/StateGoExamples.png'/>
32126              *
32127              * @param {string} to Absolute state name or relative state path. Some examples:
32128              *
32129              * - `$state.go('contact.detail')` - will go to the `contact.detail` state
32130              * - `$state.go('^')` - will go to a parent state
32131              * - `$state.go('^.sibling')` - will go to a sibling state
32132              * - `$state.go('.child.grandchild')` - will go to grandchild state
32133              *
32134              * @param {object=} params A map of the parameters that will be sent to the state, 
32135              * will populate $stateParams. Any parameters that are not specified will be inherited from currently 
32136              * defined parameters. This allows, for example, going to a sibling state that shares parameters
32137              * specified in a parent state. Parameter inheritance only works between common ancestor states, I.e.
32138              * transitioning to a sibling will get you the parameters for all parents, transitioning to a child
32139              * will get you all current parameters, etc.
32140              * @param {object=} options Options object. The options are:
32141              *
32142              * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
32143              *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
32144              * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
32145              * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
32146              *    defines which state to be relative from.
32147              * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
32148              * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params 
32149              *    have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
32150              *    use this when you want to force a reload when *everything* is the same, including search params.
32151              *
32152              * @returns {promise} A promise representing the state of the new transition.
32153              *
32154              * Possible success values:
32155              *
32156              * - $state.current
32157              *
32158              * <br/>Possible rejection values:
32159              *
32160              * - 'transition superseded' - when a newer transition has been started after this one
32161              * - 'transition prevented' - when `event.preventDefault()` has been called in a `$stateChangeStart` listener
32162              * - 'transition aborted' - when `event.preventDefault()` has been called in a `$stateNotFound` listener or
32163              *   when a `$stateNotFound` `event.retry` promise errors.
32164              * - 'transition failed' - when a state has been unsuccessfully found after 2 tries.
32165              * - *resolve error* - when an error has occurred with a `resolve`
32166              *
32167              */
32168             $state.go = function go(to, params, options) {
32169               return $state.transitionTo(to, params, extend({ inherit: true, relative: $state.$current }, options));
32170             };
32171
32172             /**
32173              * @ngdoc function
32174              * @name ui.router.state.$state#transitionTo
32175              * @methodOf ui.router.state.$state
32176              *
32177              * @description
32178              * Low-level method for transitioning to a new state. {@link ui.router.state.$state#methods_go $state.go}
32179              * uses `transitionTo` internally. `$state.go` is recommended in most situations.
32180              *
32181              * @example
32182              * <pre>
32183              * var app = angular.module('app', ['ui.router']);
32184              *
32185              * app.controller('ctrl', function ($scope, $state) {
32186              *   $scope.changeState = function () {
32187              *     $state.transitionTo('contact.detail');
32188              *   };
32189              * });
32190              * </pre>
32191              *
32192              * @param {string} to State name.
32193              * @param {object=} toParams A map of the parameters that will be sent to the state,
32194              * will populate $stateParams.
32195              * @param {object=} options Options object. The options are:
32196              *
32197              * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
32198              *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
32199              * - **`inherit`** - {boolean=false}, If `true` will inherit url parameters from current url.
32200              * - **`relative`** - {object=}, When transitioning with relative path (e.g '^'), 
32201              *    defines which state to be relative from.
32202              * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
32203              * - **`reload`** (v0.2.5) - {boolean=false|string=|object=}, If `true` will force transition even if the state or params 
32204              *    have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
32205              *    use this when you want to force a reload when *everything* is the same, including search params.
32206              *    if String, then will reload the state with the name given in reload, and any children.
32207              *    if Object, then a stateObj is expected, will reload the state found in stateObj, and any children.
32208              *
32209              * @returns {promise} A promise representing the state of the new transition. See
32210              * {@link ui.router.state.$state#methods_go $state.go}.
32211              */
32212             $state.transitionTo = function transitionTo(to, toParams, options) {
32213               toParams = toParams || {};
32214               options = extend({
32215                 location: true, inherit: false, relative: null, notify: true, reload: false, $retry: false
32216               }, options || {});
32217
32218               var from = $state.$current, fromParams = $state.params, fromPath = from.path;
32219               var evt, toState = findState(to, options.relative);
32220
32221               // Store the hash param for later (since it will be stripped out by various methods)
32222               var hash = toParams['#'];
32223
32224               if (!isDefined(toState)) {
32225                 var redirect = { to: to, toParams: toParams, options: options };
32226                 var redirectResult = handleRedirect(redirect, from.self, fromParams, options);
32227
32228                 if (redirectResult) {
32229                   return redirectResult;
32230                 }
32231
32232                 // Always retry once if the $stateNotFound was not prevented
32233                 // (handles either redirect changed or state lazy-definition)
32234                 to = redirect.to;
32235                 toParams = redirect.toParams;
32236                 options = redirect.options;
32237                 toState = findState(to, options.relative);
32238
32239                 if (!isDefined(toState)) {
32240                   if (!options.relative) throw new Error("No such state '" + to + "'");
32241                   throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'");
32242                 }
32243               }
32244               if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
32245               if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState);
32246               if (!toState.params.$$validates(toParams)) return TransitionFailed;
32247
32248               toParams = toState.params.$$values(toParams);
32249               to = toState;
32250
32251               var toPath = to.path;
32252
32253               // Starting from the root of the path, keep all levels that haven't changed
32254               var keep = 0, state = toPath[keep], locals = root.locals, toLocals = [];
32255
32256               if (!options.reload) {
32257                 while (state && state === fromPath[keep] && state.ownParams.$$equals(toParams, fromParams)) {
32258                   locals = toLocals[keep] = state.locals;
32259                   keep++;
32260                   state = toPath[keep];
32261                 }
32262               } else if (isString(options.reload) || isObject(options.reload)) {
32263                 if (isObject(options.reload) && !options.reload.name) {
32264                   throw new Error('Invalid reload state object');
32265                 }
32266                 
32267                 var reloadState = options.reload === true ? fromPath[0] : findState(options.reload);
32268                 if (options.reload && !reloadState) {
32269                   throw new Error("No such reload state '" + (isString(options.reload) ? options.reload : options.reload.name) + "'");
32270                 }
32271
32272                 while (state && state === fromPath[keep] && state !== reloadState) {
32273                   locals = toLocals[keep] = state.locals;
32274                   keep++;
32275                   state = toPath[keep];
32276                 }
32277               }
32278
32279               // If we're going to the same state and all locals are kept, we've got nothing to do.
32280               // But clear 'transition', as we still want to cancel any other pending transitions.
32281               // TODO: We may not want to bump 'transition' if we're called from a location change
32282               // that we've initiated ourselves, because we might accidentally abort a legitimate
32283               // transition initiated from code?
32284               if (shouldSkipReload(to, toParams, from, fromParams, locals, options)) {
32285                 if (hash) toParams['#'] = hash;
32286                 $state.params = toParams;
32287                 copy($state.params, $stateParams);
32288                 if (options.location && to.navigable && to.navigable.url) {
32289                   $urlRouter.push(to.navigable.url, toParams, {
32290                     $$avoidResync: true, replace: options.location === 'replace'
32291                   });
32292                   $urlRouter.update(true);
32293                 }
32294                 $state.transition = null;
32295                 return $q.when($state.current);
32296               }
32297
32298               // Filter parameters before we pass them to event handlers etc.
32299               toParams = filterByKeys(to.params.$$keys(), toParams || {});
32300
32301               // Broadcast start event and cancel the transition if requested
32302               if (options.notify) {
32303                 /**
32304                  * @ngdoc event
32305                  * @name ui.router.state.$state#$stateChangeStart
32306                  * @eventOf ui.router.state.$state
32307                  * @eventType broadcast on root scope
32308                  * @description
32309                  * Fired when the state transition **begins**. You can use `event.preventDefault()`
32310                  * to prevent the transition from happening and then the transition promise will be
32311                  * rejected with a `'transition prevented'` value.
32312                  *
32313                  * @param {Object} event Event object.
32314                  * @param {State} toState The state being transitioned to.
32315                  * @param {Object} toParams The params supplied to the `toState`.
32316                  * @param {State} fromState The current state, pre-transition.
32317                  * @param {Object} fromParams The params supplied to the `fromState`.
32318                  *
32319                  * @example
32320                  *
32321                  * <pre>
32322                  * $rootScope.$on('$stateChangeStart',
32323                  * function(event, toState, toParams, fromState, fromParams){
32324                  *     event.preventDefault();
32325                  *     // transitionTo() promise will be rejected with
32326                  *     // a 'transition prevented' error
32327                  * })
32328                  * </pre>
32329                  */
32330                 if ($rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams).defaultPrevented) {
32331                   $rootScope.$broadcast('$stateChangeCancel', to.self, toParams, from.self, fromParams);
32332                   $urlRouter.update();
32333                   return TransitionPrevented;
32334                 }
32335               }
32336
32337               // Resolve locals for the remaining states, but don't update any global state just
32338               // yet -- if anything fails to resolve the current state needs to remain untouched.
32339               // We also set up an inheritance chain for the locals here. This allows the view directive
32340               // to quickly look up the correct definition for each view in the current state. Even
32341               // though we create the locals object itself outside resolveState(), it is initially
32342               // empty and gets filled asynchronously. We need to keep track of the promise for the
32343               // (fully resolved) current locals, and pass this down the chain.
32344               var resolved = $q.when(locals);
32345
32346               for (var l = keep; l < toPath.length; l++, state = toPath[l]) {
32347                 locals = toLocals[l] = inherit(locals);
32348                 resolved = resolveState(state, toParams, state === to, resolved, locals, options);
32349               }
32350
32351               // Once everything is resolved, we are ready to perform the actual transition
32352               // and return a promise for the new state. We also keep track of what the
32353               // current promise is, so that we can detect overlapping transitions and
32354               // keep only the outcome of the last transition.
32355               var transition = $state.transition = resolved.then(function () {
32356                 var l, entering, exiting;
32357
32358                 if ($state.transition !== transition) return TransitionSuperseded;
32359
32360                 // Exit 'from' states not kept
32361                 for (l = fromPath.length - 1; l >= keep; l--) {
32362                   exiting = fromPath[l];
32363                   if (exiting.self.onExit) {
32364                     $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals);
32365                   }
32366                   exiting.locals = null;
32367                 }
32368
32369                 // Enter 'to' states not kept
32370                 for (l = keep; l < toPath.length; l++) {
32371                   entering = toPath[l];
32372                   entering.locals = toLocals[l];
32373                   if (entering.self.onEnter) {
32374                     $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
32375                   }
32376                 }
32377
32378                 // Re-add the saved hash before we start returning things
32379                 if (hash) toParams['#'] = hash;
32380
32381                 // Run it again, to catch any transitions in callbacks
32382                 if ($state.transition !== transition) return TransitionSuperseded;
32383
32384                 // Update globals in $state
32385                 $state.$current = to;
32386                 $state.current = to.self;
32387                 $state.params = toParams;
32388                 copy($state.params, $stateParams);
32389                 $state.transition = null;
32390
32391                 if (options.location && to.navigable) {
32392                   $urlRouter.push(to.navigable.url, to.navigable.locals.globals.$stateParams, {
32393                     $$avoidResync: true, replace: options.location === 'replace'
32394                   });
32395                 }
32396
32397                 if (options.notify) {
32398                 /**
32399                  * @ngdoc event
32400                  * @name ui.router.state.$state#$stateChangeSuccess
32401                  * @eventOf ui.router.state.$state
32402                  * @eventType broadcast on root scope
32403                  * @description
32404                  * Fired once the state transition is **complete**.
32405                  *
32406                  * @param {Object} event Event object.
32407                  * @param {State} toState The state being transitioned to.
32408                  * @param {Object} toParams The params supplied to the `toState`.
32409                  * @param {State} fromState The current state, pre-transition.
32410                  * @param {Object} fromParams The params supplied to the `fromState`.
32411                  */
32412                   $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams);
32413                 }
32414                 $urlRouter.update(true);
32415
32416                 return $state.current;
32417               }, function (error) {
32418                 if ($state.transition !== transition) return TransitionSuperseded;
32419
32420                 $state.transition = null;
32421                 /**
32422                  * @ngdoc event
32423                  * @name ui.router.state.$state#$stateChangeError
32424                  * @eventOf ui.router.state.$state
32425                  * @eventType broadcast on root scope
32426                  * @description
32427                  * Fired when an **error occurs** during transition. It's important to note that if you
32428                  * have any errors in your resolve functions (javascript errors, non-existent services, etc)
32429                  * they will not throw traditionally. You must listen for this $stateChangeError event to
32430                  * catch **ALL** errors.
32431                  *
32432                  * @param {Object} event Event object.
32433                  * @param {State} toState The state being transitioned to.
32434                  * @param {Object} toParams The params supplied to the `toState`.
32435                  * @param {State} fromState The current state, pre-transition.
32436                  * @param {Object} fromParams The params supplied to the `fromState`.
32437                  * @param {Error} error The resolve error object.
32438                  */
32439                 evt = $rootScope.$broadcast('$stateChangeError', to.self, toParams, from.self, fromParams, error);
32440
32441                 if (!evt.defaultPrevented) {
32442                     $urlRouter.update();
32443                 }
32444
32445                 return $q.reject(error);
32446               });
32447
32448               return transition;
32449             };
32450
32451             /**
32452              * @ngdoc function
32453              * @name ui.router.state.$state#is
32454              * @methodOf ui.router.state.$state
32455              *
32456              * @description
32457              * Similar to {@link ui.router.state.$state#methods_includes $state.includes},
32458              * but only checks for the full state name. If params is supplied then it will be
32459              * tested for strict equality against the current active params object, so all params
32460              * must match with none missing and no extras.
32461              *
32462              * @example
32463              * <pre>
32464              * $state.$current.name = 'contacts.details.item';
32465              *
32466              * // absolute name
32467              * $state.is('contact.details.item'); // returns true
32468              * $state.is(contactDetailItemStateObject); // returns true
32469              *
32470              * // relative name (. and ^), typically from a template
32471              * // E.g. from the 'contacts.details' template
32472              * <div ng-class="{highlighted: $state.is('.item')}">Item</div>
32473              * </pre>
32474              *
32475              * @param {string|object} stateOrName The state name (absolute or relative) or state object you'd like to check.
32476              * @param {object=} params A param object, e.g. `{sectionId: section.id}`, that you'd like
32477              * to test against the current active state.
32478              * @param {object=} options An options object.  The options are:
32479              *
32480              * - **`relative`** - {string|object} -  If `stateOrName` is a relative state name and `options.relative` is set, .is will
32481              * test relative to `options.relative` state (or name).
32482              *
32483              * @returns {boolean} Returns true if it is the state.
32484              */
32485             $state.is = function is(stateOrName, params, options) {
32486               options = extend({ relative: $state.$current }, options || {});
32487               var state = findState(stateOrName, options.relative);
32488
32489               if (!isDefined(state)) { return undefined; }
32490               if ($state.$current !== state) { return false; }
32491               return params ? equalForKeys(state.params.$$values(params), $stateParams) : true;
32492             };
32493
32494             /**
32495              * @ngdoc function
32496              * @name ui.router.state.$state#includes
32497              * @methodOf ui.router.state.$state
32498              *
32499              * @description
32500              * A method to determine if the current active state is equal to or is the child of the
32501              * state stateName. If any params are passed then they will be tested for a match as well.
32502              * Not all the parameters need to be passed, just the ones you'd like to test for equality.
32503              *
32504              * @example
32505              * Partial and relative names
32506              * <pre>
32507              * $state.$current.name = 'contacts.details.item';
32508              *
32509              * // Using partial names
32510              * $state.includes("contacts"); // returns true
32511              * $state.includes("contacts.details"); // returns true
32512              * $state.includes("contacts.details.item"); // returns true
32513              * $state.includes("contacts.list"); // returns false
32514              * $state.includes("about"); // returns false
32515              *
32516              * // Using relative names (. and ^), typically from a template
32517              * // E.g. from the 'contacts.details' template
32518              * <div ng-class="{highlighted: $state.includes('.item')}">Item</div>
32519              * </pre>
32520              *
32521              * Basic globbing patterns
32522              * <pre>
32523              * $state.$current.name = 'contacts.details.item.url';
32524              *
32525              * $state.includes("*.details.*.*"); // returns true
32526              * $state.includes("*.details.**"); // returns true
32527              * $state.includes("**.item.**"); // returns true
32528              * $state.includes("*.details.item.url"); // returns true
32529              * $state.includes("*.details.*.url"); // returns true
32530              * $state.includes("*.details.*"); // returns false
32531              * $state.includes("item.**"); // returns false
32532              * </pre>
32533              *
32534              * @param {string} stateOrName A partial name, relative name, or glob pattern
32535              * to be searched for within the current state name.
32536              * @param {object=} params A param object, e.g. `{sectionId: section.id}`,
32537              * that you'd like to test against the current active state.
32538              * @param {object=} options An options object.  The options are:
32539              *
32540              * - **`relative`** - {string|object=} -  If `stateOrName` is a relative state reference and `options.relative` is set,
32541              * .includes will test relative to `options.relative` state (or name).
32542              *
32543              * @returns {boolean} Returns true if it does include the state
32544              */
32545             $state.includes = function includes(stateOrName, params, options) {
32546               options = extend({ relative: $state.$current }, options || {});
32547               if (isString(stateOrName) && isGlob(stateOrName)) {
32548                 if (!doesStateMatchGlob(stateOrName)) {
32549                   return false;
32550                 }
32551                 stateOrName = $state.$current.name;
32552               }
32553
32554               var state = findState(stateOrName, options.relative);
32555               if (!isDefined(state)) { return undefined; }
32556               if (!isDefined($state.$current.includes[state.name])) { return false; }
32557               return params ? equalForKeys(state.params.$$values(params), $stateParams, objectKeys(params)) : true;
32558             };
32559
32560
32561             /**
32562              * @ngdoc function
32563              * @name ui.router.state.$state#href
32564              * @methodOf ui.router.state.$state
32565              *
32566              * @description
32567              * A url generation method that returns the compiled url for the given state populated with the given params.
32568              *
32569              * @example
32570              * <pre>
32571              * expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
32572              * </pre>
32573              *
32574              * @param {string|object} stateOrName The state name or state object you'd like to generate a url from.
32575              * @param {object=} params An object of parameter values to fill the state's required parameters.
32576              * @param {object=} options Options object. The options are:
32577              *
32578              * - **`lossy`** - {boolean=true} -  If true, and if there is no url associated with the state provided in the
32579              *    first parameter, then the constructed href url will be built from the first navigable ancestor (aka
32580              *    ancestor with a valid url).
32581              * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
32582              * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
32583              *    defines which state to be relative from.
32584              * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
32585              * 
32586              * @returns {string} compiled state url
32587              */
32588             $state.href = function href(stateOrName, params, options) {
32589               options = extend({
32590                 lossy:    true,
32591                 inherit:  true,
32592                 absolute: false,
32593                 relative: $state.$current
32594               }, options || {});
32595
32596               var state = findState(stateOrName, options.relative);
32597
32598               if (!isDefined(state)) return null;
32599               if (options.inherit) params = inheritParams($stateParams, params || {}, $state.$current, state);
32600               
32601               var nav = (state && options.lossy) ? state.navigable : state;
32602
32603               if (!nav || nav.url === undefined || nav.url === null) {
32604                 return null;
32605               }
32606               return $urlRouter.href(nav.url, filterByKeys(state.params.$$keys().concat('#'), params || {}), {
32607                 absolute: options.absolute
32608               });
32609             };
32610
32611             /**
32612              * @ngdoc function
32613              * @name ui.router.state.$state#get
32614              * @methodOf ui.router.state.$state
32615              *
32616              * @description
32617              * Returns the state configuration object for any specific state or all states.
32618              *
32619              * @param {string|object=} stateOrName (absolute or relative) If provided, will only get the config for
32620              * the requested state. If not provided, returns an array of ALL state configs.
32621              * @param {string|object=} context When stateOrName is a relative state reference, the state will be retrieved relative to context.
32622              * @returns {Object|Array} State configuration object or array of all objects.
32623              */
32624             $state.get = function (stateOrName, context) {
32625               if (arguments.length === 0) return map(objectKeys(states), function(name) { return states[name].self; });
32626               var state = findState(stateOrName, context || $state.$current);
32627               return (state && state.self) ? state.self : null;
32628             };
32629
32630             function resolveState(state, params, paramsAreFiltered, inherited, dst, options) {
32631               // Make a restricted $stateParams with only the parameters that apply to this state if
32632               // necessary. In addition to being available to the controller and onEnter/onExit callbacks,
32633               // we also need $stateParams to be available for any $injector calls we make during the
32634               // dependency resolution process.
32635               var $stateParams = (paramsAreFiltered) ? params : filterByKeys(state.params.$$keys(), params);
32636               var locals = { $stateParams: $stateParams };
32637
32638               // Resolve 'global' dependencies for the state, i.e. those not specific to a view.
32639               // We're also including $stateParams in this; that way the parameters are restricted
32640               // to the set that should be visible to the state, and are independent of when we update
32641               // the global $state and $stateParams values.
32642               dst.resolve = $resolve.resolve(state.resolve, locals, dst.resolve, state);
32643               var promises = [dst.resolve.then(function (globals) {
32644                 dst.globals = globals;
32645               })];
32646               if (inherited) promises.push(inherited);
32647
32648               function resolveViews() {
32649                 var viewsPromises = [];
32650
32651                 // Resolve template and dependencies for all views.
32652                 forEach(state.views, function (view, name) {
32653                   var injectables = (view.resolve && view.resolve !== state.resolve ? view.resolve : {});
32654                   injectables.$template = [ function () {
32655                     return $view.load(name, { view: view, locals: dst.globals, params: $stateParams, notify: options.notify }) || '';
32656                   }];
32657
32658                   viewsPromises.push($resolve.resolve(injectables, dst.globals, dst.resolve, state).then(function (result) {
32659                     // References to the controller (only instantiated at link time)
32660                     if (isFunction(view.controllerProvider) || isArray(view.controllerProvider)) {
32661                       var injectLocals = angular.extend({}, injectables, dst.globals);
32662                       result.$$controller = $injector.invoke(view.controllerProvider, null, injectLocals);
32663                     } else {
32664                       result.$$controller = view.controller;
32665                     }
32666                     // Provide access to the state itself for internal use
32667                     result.$$state = state;
32668                     result.$$controllerAs = view.controllerAs;
32669                     dst[name] = result;
32670                   }));
32671                 });
32672
32673                 return $q.all(viewsPromises).then(function(){
32674                   return dst.globals;
32675                 });
32676               }
32677
32678               // Wait for all the promises and then return the activation object
32679               return $q.all(promises).then(resolveViews).then(function (values) {
32680                 return dst;
32681               });
32682             }
32683
32684             return $state;
32685           }
32686
32687           function shouldSkipReload(to, toParams, from, fromParams, locals, options) {
32688             // Return true if there are no differences in non-search (path/object) params, false if there are differences
32689             function nonSearchParamsEqual(fromAndToState, fromParams, toParams) {
32690               // Identify whether all the parameters that differ between `fromParams` and `toParams` were search params.
32691               function notSearchParam(key) {
32692                 return fromAndToState.params[key].location != "search";
32693               }
32694               var nonQueryParamKeys = fromAndToState.params.$$keys().filter(notSearchParam);
32695               var nonQueryParams = pick.apply({}, [fromAndToState.params].concat(nonQueryParamKeys));
32696               var nonQueryParamSet = new $$UMFP.ParamSet(nonQueryParams);
32697               return nonQueryParamSet.$$equals(fromParams, toParams);
32698             }
32699
32700             // If reload was not explicitly requested
32701             // and we're transitioning to the same state we're already in
32702             // and    the locals didn't change
32703             //     or they changed in a way that doesn't merit reloading
32704             //        (reloadOnParams:false, or reloadOnSearch.false and only search params changed)
32705             // Then return true.
32706             if (!options.reload && to === from &&
32707               (locals === from.locals || (to.self.reloadOnSearch === false && nonSearchParamsEqual(from, fromParams, toParams)))) {
32708               return true;
32709             }
32710           }
32711         }
32712
32713         angular.module('ui.router.state')
32714           .value('$stateParams', {})
32715           .provider('$state', $StateProvider);
32716
32717
32718         $ViewProvider.$inject = [];
32719         function $ViewProvider() {
32720
32721           this.$get = $get;
32722           /**
32723            * @ngdoc object
32724            * @name ui.router.state.$view
32725            *
32726            * @requires ui.router.util.$templateFactory
32727            * @requires $rootScope
32728            *
32729            * @description
32730            *
32731            */
32732           $get.$inject = ['$rootScope', '$templateFactory'];
32733           function $get(   $rootScope,   $templateFactory) {
32734             return {
32735               // $view.load('full.viewName', { template: ..., controller: ..., resolve: ..., async: false, params: ... })
32736               /**
32737                * @ngdoc function
32738                * @name ui.router.state.$view#load
32739                * @methodOf ui.router.state.$view
32740                *
32741                * @description
32742                *
32743                * @param {string} name name
32744                * @param {object} options option object.
32745                */
32746               load: function load(name, options) {
32747                 var result, defaults = {
32748                   template: null, controller: null, view: null, locals: null, notify: true, async: true, params: {}
32749                 };
32750                 options = extend(defaults, options);
32751
32752                 if (options.view) {
32753                   result = $templateFactory.fromConfig(options.view, options.params, options.locals);
32754                 }
32755                 if (result && options.notify) {
32756                 /**
32757                  * @ngdoc event
32758                  * @name ui.router.state.$state#$viewContentLoading
32759                  * @eventOf ui.router.state.$view
32760                  * @eventType broadcast on root scope
32761                  * @description
32762                  *
32763                  * Fired once the view **begins loading**, *before* the DOM is rendered.
32764                  *
32765                  * @param {Object} event Event object.
32766                  * @param {Object} viewConfig The view config properties (template, controller, etc).
32767                  *
32768                  * @example
32769                  *
32770                  * <pre>
32771                  * $scope.$on('$viewContentLoading',
32772                  * function(event, viewConfig){
32773                  *     // Access to all the view config properties.
32774                  *     // and one special property 'targetView'
32775                  *     // viewConfig.targetView
32776                  * });
32777                  * </pre>
32778                  */
32779                   $rootScope.$broadcast('$viewContentLoading', options);
32780                 }
32781                 return result;
32782               }
32783             };
32784           }
32785         }
32786
32787         angular.module('ui.router.state').provider('$view', $ViewProvider);
32788
32789         /**
32790          * @ngdoc object
32791          * @name ui.router.state.$uiViewScrollProvider
32792          *
32793          * @description
32794          * Provider that returns the {@link ui.router.state.$uiViewScroll} service function.
32795          */
32796         function $ViewScrollProvider() {
32797
32798           var useAnchorScroll = false;
32799
32800           /**
32801            * @ngdoc function
32802            * @name ui.router.state.$uiViewScrollProvider#useAnchorScroll
32803            * @methodOf ui.router.state.$uiViewScrollProvider
32804            *
32805            * @description
32806            * Reverts back to using the core [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) service for
32807            * scrolling based on the url anchor.
32808            */
32809           this.useAnchorScroll = function () {
32810             useAnchorScroll = true;
32811           };
32812
32813           /**
32814            * @ngdoc object
32815            * @name ui.router.state.$uiViewScroll
32816            *
32817            * @requires $anchorScroll
32818            * @requires $timeout
32819            *
32820            * @description
32821            * When called with a jqLite element, it scrolls the element into view (after a
32822            * `$timeout` so the DOM has time to refresh).
32823            *
32824            * If you prefer to rely on `$anchorScroll` to scroll the view to the anchor,
32825            * this can be enabled by calling {@link ui.router.state.$uiViewScrollProvider#methods_useAnchorScroll `$uiViewScrollProvider.useAnchorScroll()`}.
32826            */
32827           this.$get = ['$anchorScroll', '$timeout', function ($anchorScroll, $timeout) {
32828             if (useAnchorScroll) {
32829               return $anchorScroll;
32830             }
32831
32832             return function ($element) {
32833               return $timeout(function () {
32834                 $element[0].scrollIntoView();
32835               }, 0, false);
32836             };
32837           }];
32838         }
32839
32840         angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider);
32841
32842         /**
32843          * @ngdoc directive
32844          * @name ui.router.state.directive:ui-view
32845          *
32846          * @requires ui.router.state.$state
32847          * @requires $compile
32848          * @requires $controller
32849          * @requires $injector
32850          * @requires ui.router.state.$uiViewScroll
32851          * @requires $document
32852          *
32853          * @restrict ECA
32854          *
32855          * @description
32856          * The ui-view directive tells $state where to place your templates.
32857          *
32858          * @param {string=} name A view name. The name should be unique amongst the other views in the
32859          * same state. You can have views of the same name that live in different states.
32860          *
32861          * @param {string=} autoscroll It allows you to set the scroll behavior of the browser window
32862          * when a view is populated. By default, $anchorScroll is overridden by ui-router's custom scroll
32863          * service, {@link ui.router.state.$uiViewScroll}. This custom service let's you
32864          * scroll ui-view elements into view when they are populated during a state activation.
32865          *
32866          * *Note: To revert back to old [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll)
32867          * functionality, call `$uiViewScrollProvider.useAnchorScroll()`.*
32868          *
32869          * @param {string=} onload Expression to evaluate whenever the view updates.
32870          * 
32871          * @example
32872          * A view can be unnamed or named. 
32873          * <pre>
32874          * <!-- Unnamed -->
32875          * <div ui-view></div> 
32876          * 
32877          * <!-- Named -->
32878          * <div ui-view="viewName"></div>
32879          * </pre>
32880          *
32881          * You can only have one unnamed view within any template (or root html). If you are only using a 
32882          * single view and it is unnamed then you can populate it like so:
32883          * <pre>
32884          * <div ui-view></div> 
32885          * $stateProvider.state("home", {
32886          *   template: "<h1>HELLO!</h1>"
32887          * })
32888          * </pre>
32889          * 
32890          * The above is a convenient shortcut equivalent to specifying your view explicitly with the {@link ui.router.state.$stateProvider#views `views`}
32891          * config property, by name, in this case an empty name:
32892          * <pre>
32893          * $stateProvider.state("home", {
32894          *   views: {
32895          *     "": {
32896          *       template: "<h1>HELLO!</h1>"
32897          *     }
32898          *   }    
32899          * })
32900          * </pre>
32901          * 
32902          * But typically you'll only use the views property if you name your view or have more than one view 
32903          * in the same template. There's not really a compelling reason to name a view if its the only one, 
32904          * but you could if you wanted, like so:
32905          * <pre>
32906          * <div ui-view="main"></div>
32907          * </pre> 
32908          * <pre>
32909          * $stateProvider.state("home", {
32910          *   views: {
32911          *     "main": {
32912          *       template: "<h1>HELLO!</h1>"
32913          *     }
32914          *   }    
32915          * })
32916          * </pre>
32917          * 
32918          * Really though, you'll use views to set up multiple views:
32919          * <pre>
32920          * <div ui-view></div>
32921          * <div ui-view="chart"></div> 
32922          * <div ui-view="data"></div> 
32923          * </pre>
32924          * 
32925          * <pre>
32926          * $stateProvider.state("home", {
32927          *   views: {
32928          *     "": {
32929          *       template: "<h1>HELLO!</h1>"
32930          *     },
32931          *     "chart": {
32932          *       template: "<chart_thing/>"
32933          *     },
32934          *     "data": {
32935          *       template: "<data_thing/>"
32936          *     }
32937          *   }    
32938          * })
32939          * </pre>
32940          *
32941          * Examples for `autoscroll`:
32942          *
32943          * <pre>
32944          * <!-- If autoscroll present with no expression,
32945          *      then scroll ui-view into view -->
32946          * <ui-view autoscroll/>
32947          *
32948          * <!-- If autoscroll present with valid expression,
32949          *      then scroll ui-view into view if expression evaluates to true -->
32950          * <ui-view autoscroll='true'/>
32951          * <ui-view autoscroll='false'/>
32952          * <ui-view autoscroll='scopeVariable'/>
32953          * </pre>
32954          */
32955         $ViewDirective.$inject = ['$state', '$injector', '$uiViewScroll', '$interpolate'];
32956         function $ViewDirective(   $state,   $injector,   $uiViewScroll,   $interpolate) {
32957
32958           function getService() {
32959             return ($injector.has) ? function(service) {
32960               return $injector.has(service) ? $injector.get(service) : null;
32961             } : function(service) {
32962               try {
32963                 return $injector.get(service);
32964               } catch (e) {
32965                 return null;
32966               }
32967             };
32968           }
32969
32970           var service = getService(),
32971               $animator = service('$animator'),
32972               $animate = service('$animate');
32973
32974           // Returns a set of DOM manipulation functions based on which Angular version
32975           // it should use
32976           function getRenderer(attrs, scope) {
32977             var statics = function() {
32978               return {
32979                 enter: function (element, target, cb) { target.after(element); cb(); },
32980                 leave: function (element, cb) { element.remove(); cb(); }
32981               };
32982             };
32983
32984             if ($animate) {
32985               return {
32986                 enter: function(element, target, cb) {
32987                   var promise = $animate.enter(element, null, target, cb);
32988                   if (promise && promise.then) promise.then(cb);
32989                 },
32990                 leave: function(element, cb) {
32991                   var promise = $animate.leave(element, cb);
32992                   if (promise && promise.then) promise.then(cb);
32993                 }
32994               };
32995             }
32996
32997             if ($animator) {
32998               var animate = $animator && $animator(scope, attrs);
32999
33000               return {
33001                 enter: function(element, target, cb) {animate.enter(element, null, target); cb(); },
33002                 leave: function(element, cb) { animate.leave(element); cb(); }
33003               };
33004             }
33005
33006             return statics();
33007           }
33008
33009           var directive = {
33010             restrict: 'ECA',
33011             terminal: true,
33012             priority: 400,
33013             transclude: 'element',
33014             compile: function (tElement, tAttrs, $transclude) {
33015               return function (scope, $element, attrs) {
33016                 var previousEl, currentEl, currentScope, latestLocals,
33017                     onloadExp     = attrs.onload || '',
33018                     autoScrollExp = attrs.autoscroll,
33019                     renderer      = getRenderer(attrs, scope);
33020
33021                 scope.$on('$stateChangeSuccess', function() {
33022                   updateView(false);
33023                 });
33024                 scope.$on('$viewContentLoading', function() {
33025                   updateView(false);
33026                 });
33027
33028                 updateView(true);
33029
33030                 function cleanupLastView() {
33031                   if (previousEl) {
33032                     previousEl.remove();
33033                     previousEl = null;
33034                   }
33035
33036                   if (currentScope) {
33037                     currentScope.$destroy();
33038                     currentScope = null;
33039                   }
33040
33041                   if (currentEl) {
33042                     renderer.leave(currentEl, function() {
33043                       previousEl = null;
33044                     });
33045
33046                     previousEl = currentEl;
33047                     currentEl = null;
33048                   }
33049                 }
33050
33051                 function updateView(firstTime) {
33052                   var newScope,
33053                       name            = getUiViewName(scope, attrs, $element, $interpolate),
33054                       previousLocals  = name && $state.$current && $state.$current.locals[name];
33055
33056                   if (!firstTime && previousLocals === latestLocals) return; // nothing to do
33057                   newScope = scope.$new();
33058                   latestLocals = $state.$current.locals[name];
33059
33060                   var clone = $transclude(newScope, function(clone) {
33061                     renderer.enter(clone, $element, function onUiViewEnter() {
33062                       if(currentScope) {
33063                         currentScope.$emit('$viewContentAnimationEnded');
33064                       }
33065
33066                       if (angular.isDefined(autoScrollExp) && !autoScrollExp || scope.$eval(autoScrollExp)) {
33067                         $uiViewScroll(clone);
33068                       }
33069                     });
33070                     cleanupLastView();
33071                   });
33072
33073                   currentEl = clone;
33074                   currentScope = newScope;
33075                   /**
33076                    * @ngdoc event
33077                    * @name ui.router.state.directive:ui-view#$viewContentLoaded
33078                    * @eventOf ui.router.state.directive:ui-view
33079                    * @eventType emits on ui-view directive scope
33080                    * @description           *
33081                    * Fired once the view is **loaded**, *after* the DOM is rendered.
33082                    *
33083                    * @param {Object} event Event object.
33084                    */
33085                   currentScope.$emit('$viewContentLoaded');
33086                   currentScope.$eval(onloadExp);
33087                 }
33088               };
33089             }
33090           };
33091
33092           return directive;
33093         }
33094
33095         $ViewDirectiveFill.$inject = ['$compile', '$controller', '$state', '$interpolate'];
33096         function $ViewDirectiveFill (  $compile,   $controller,   $state,   $interpolate) {
33097           return {
33098             restrict: 'ECA',
33099             priority: -400,
33100             compile: function (tElement) {
33101               var initial = tElement.html();
33102               return function (scope, $element, attrs) {
33103                 var current = $state.$current,
33104                     name = getUiViewName(scope, attrs, $element, $interpolate),
33105                     locals  = current && current.locals[name];
33106
33107                 if (! locals) {
33108                   return;
33109                 }
33110
33111                 $element.data('$uiView', { name: name, state: locals.$$state });
33112                 $element.html(locals.$template ? locals.$template : initial);
33113
33114                 var link = $compile($element.contents());
33115
33116                 if (locals.$$controller) {
33117                   locals.$scope = scope;
33118                   locals.$element = $element;
33119                   var controller = $controller(locals.$$controller, locals);
33120                   if (locals.$$controllerAs) {
33121                     scope[locals.$$controllerAs] = controller;
33122                   }
33123                   $element.data('$ngControllerController', controller);
33124                   $element.children().data('$ngControllerController', controller);
33125                 }
33126
33127                 link(scope);
33128               };
33129             }
33130           };
33131         }
33132
33133         /**
33134          * Shared ui-view code for both directives:
33135          * Given scope, element, and its attributes, return the view's name
33136          */
33137         function getUiViewName(scope, attrs, element, $interpolate) {
33138           var name = $interpolate(attrs.uiView || attrs.name || '')(scope);
33139           var inherited = element.inheritedData('$uiView');
33140           return name.indexOf('@') >= 0 ?  name :  (name + '@' + (inherited ? inherited.state.name : ''));
33141         }
33142
33143         angular.module('ui.router.state').directive('uiView', $ViewDirective);
33144         angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill);
33145
33146         function parseStateRef(ref, current) {
33147           var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed;
33148           if (preparsed) ref = current + '(' + preparsed[1] + ')';
33149           parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
33150           if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'");
33151           return { state: parsed[1], paramExpr: parsed[3] || null };
33152         }
33153
33154         function stateContext(el) {
33155           var stateData = el.parent().inheritedData('$uiView');
33156
33157           if (stateData && stateData.state && stateData.state.name) {
33158             return stateData.state;
33159           }
33160         }
33161
33162         /**
33163          * @ngdoc directive
33164          * @name ui.router.state.directive:ui-sref
33165          *
33166          * @requires ui.router.state.$state
33167          * @requires $timeout
33168          *
33169          * @restrict A
33170          *
33171          * @description
33172          * A directive that binds a link (`<a>` tag) to a state. If the state has an associated 
33173          * URL, the directive will automatically generate & update the `href` attribute via 
33174          * the {@link ui.router.state.$state#methods_href $state.href()} method. Clicking 
33175          * the link will trigger a state transition with optional parameters. 
33176          *
33177          * Also middle-clicking, right-clicking, and ctrl-clicking on the link will be 
33178          * handled natively by the browser.
33179          *
33180          * You can also use relative state paths within ui-sref, just like the relative 
33181          * paths passed to `$state.go()`. You just need to be aware that the path is relative
33182          * to the state that the link lives in, in other words the state that loaded the 
33183          * template containing the link.
33184          *
33185          * You can specify options to pass to {@link ui.router.state.$state#go $state.go()}
33186          * using the `ui-sref-opts` attribute. Options are restricted to `location`, `inherit`,
33187          * and `reload`.
33188          *
33189          * @example
33190          * Here's an example of how you'd use ui-sref and how it would compile. If you have the 
33191          * following template:
33192          * <pre>
33193          * <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> | <a ui-sref="{page: 2}">Next page</a>
33194          * 
33195          * <ul>
33196          *     <li ng-repeat="contact in contacts">
33197          *         <a ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a>
33198          *     </li>
33199          * </ul>
33200          * </pre>
33201          * 
33202          * Then the compiled html would be (assuming Html5Mode is off and current state is contacts):
33203          * <pre>
33204          * <a href="#/home" ui-sref="home">Home</a> | <a href="#/about" ui-sref="about">About</a> | <a href="#/contacts?page=2" ui-sref="{page: 2}">Next page</a>
33205          * 
33206          * <ul>
33207          *     <li ng-repeat="contact in contacts">
33208          *         <a href="#/contacts/1" ui-sref="contacts.detail({ id: contact.id })">Joe</a>
33209          *     </li>
33210          *     <li ng-repeat="contact in contacts">
33211          *         <a href="#/contacts/2" ui-sref="contacts.detail({ id: contact.id })">Alice</a>
33212          *     </li>
33213          *     <li ng-repeat="contact in contacts">
33214          *         <a href="#/contacts/3" ui-sref="contacts.detail({ id: contact.id })">Bob</a>
33215          *     </li>
33216          * </ul>
33217          *
33218          * <a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
33219          * </pre>
33220          *
33221          * @param {string} ui-sref 'stateName' can be any valid absolute or relative state
33222          * @param {Object} ui-sref-opts options to pass to {@link ui.router.state.$state#go $state.go()}
33223          */
33224         $StateRefDirective.$inject = ['$state', '$timeout'];
33225         function $StateRefDirective($state, $timeout) {
33226           var allowedOptions = ['location', 'inherit', 'reload', 'absolute'];
33227
33228           return {
33229             restrict: 'A',
33230             require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
33231             link: function(scope, element, attrs, uiSrefActive) {
33232               var ref = parseStateRef(attrs.uiSref, $state.current.name);
33233               var params = null, url = null, base = stateContext(element) || $state.$current;
33234               // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
33235               var hrefKind = Object.prototype.toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
33236                          'xlink:href' : 'href';
33237               var newHref = null, isAnchor = element.prop("tagName").toUpperCase() === "A";
33238               var isForm = element[0].nodeName === "FORM";
33239               var attr = isForm ? "action" : hrefKind, nav = true;
33240
33241               var options = { relative: base, inherit: true };
33242               var optionsOverride = scope.$eval(attrs.uiSrefOpts) || {};
33243
33244               angular.forEach(allowedOptions, function(option) {
33245                 if (option in optionsOverride) {
33246                   options[option] = optionsOverride[option];
33247                 }
33248               });
33249
33250               var update = function(newVal) {
33251                 if (newVal) params = angular.copy(newVal);
33252                 if (!nav) return;
33253
33254                 newHref = $state.href(ref.state, params, options);
33255
33256                 var activeDirective = uiSrefActive[1] || uiSrefActive[0];
33257                 if (activeDirective) {
33258                   activeDirective.$$addStateInfo(ref.state, params);
33259                 }
33260                 if (newHref === null) {
33261                   nav = false;
33262                   return false;
33263                 }
33264                 attrs.$set(attr, newHref);
33265               };
33266
33267               if (ref.paramExpr) {
33268                 scope.$watch(ref.paramExpr, function(newVal, oldVal) {
33269                   if (newVal !== params) update(newVal);
33270                 }, true);
33271                 params = angular.copy(scope.$eval(ref.paramExpr));
33272               }
33273               update();
33274
33275               if (isForm) return;
33276
33277               element.bind("click", function(e) {
33278                 var button = e.which || e.button;
33279                 if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) {
33280                   // HACK: This is to allow ng-clicks to be processed before the transition is initiated:
33281                   var transition = $timeout(function() {
33282                     $state.go(ref.state, params, options);
33283                   });
33284                   e.preventDefault();
33285
33286                   // if the state has no URL, ignore one preventDefault from the <a> directive.
33287                   var ignorePreventDefaultCount = isAnchor && !newHref ? 1: 0;
33288                   e.preventDefault = function() {
33289                     if (ignorePreventDefaultCount-- <= 0)
33290                       $timeout.cancel(transition);
33291                   };
33292                 }
33293               });
33294             }
33295           };
33296         }
33297
33298         /**
33299          * @ngdoc directive
33300          * @name ui.router.state.directive:ui-sref-active
33301          *
33302          * @requires ui.router.state.$state
33303          * @requires ui.router.state.$stateParams
33304          * @requires $interpolate
33305          *
33306          * @restrict A
33307          *
33308          * @description
33309          * A directive working alongside ui-sref to add classes to an element when the
33310          * related ui-sref directive's state is active, and removing them when it is inactive.
33311          * The primary use-case is to simplify the special appearance of navigation menus
33312          * relying on `ui-sref`, by having the "active" state's menu button appear different,
33313          * distinguishing it from the inactive menu items.
33314          *
33315          * ui-sref-active can live on the same element as ui-sref or on a parent element. The first
33316          * ui-sref-active found at the same level or above the ui-sref will be used.
33317          *
33318          * Will activate when the ui-sref's target state or any child state is active. If you
33319          * need to activate only when the ui-sref target state is active and *not* any of
33320          * it's children, then you will use
33321          * {@link ui.router.state.directive:ui-sref-active-eq ui-sref-active-eq}
33322          *
33323          * @example
33324          * Given the following template:
33325          * <pre>
33326          * <ul>
33327          *   <li ui-sref-active="active" class="item">
33328          *     <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
33329          *   </li>
33330          * </ul>
33331          * </pre>
33332          *
33333          *
33334          * When the app state is "app.user" (or any children states), and contains the state parameter "user" with value "bilbobaggins",
33335          * the resulting HTML will appear as (note the 'active' class):
33336          * <pre>
33337          * <ul>
33338          *   <li ui-sref-active="active" class="item active">
33339          *     <a ui-sref="app.user({user: 'bilbobaggins'})" href="/users/bilbobaggins">@bilbobaggins</a>
33340          *   </li>
33341          * </ul>
33342          * </pre>
33343          *
33344          * The class name is interpolated **once** during the directives link time (any further changes to the
33345          * interpolated value are ignored).
33346          *
33347          * Multiple classes may be specified in a space-separated format:
33348          * <pre>
33349          * <ul>
33350          *   <li ui-sref-active='class1 class2 class3'>
33351          *     <a ui-sref="app.user">link</a>
33352          *   </li>
33353          * </ul>
33354          * </pre>
33355          */
33356
33357         /**
33358          * @ngdoc directive
33359          * @name ui.router.state.directive:ui-sref-active-eq
33360          *
33361          * @requires ui.router.state.$state
33362          * @requires ui.router.state.$stateParams
33363          * @requires $interpolate
33364          *
33365          * @restrict A
33366          *
33367          * @description
33368          * The same as {@link ui.router.state.directive:ui-sref-active ui-sref-active} but will only activate
33369          * when the exact target state used in the `ui-sref` is active; no child states.
33370          *
33371          */
33372         $StateRefActiveDirective.$inject = ['$state', '$stateParams', '$interpolate'];
33373         function $StateRefActiveDirective($state, $stateParams, $interpolate) {
33374           return  {
33375             restrict: "A",
33376             controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
33377               var states = [], activeClass;
33378
33379               // There probably isn't much point in $observing this
33380               // uiSrefActive and uiSrefActiveEq share the same directive object with some
33381               // slight difference in logic routing
33382               activeClass = $interpolate($attrs.uiSrefActiveEq || $attrs.uiSrefActive || '', false)($scope);
33383
33384               // Allow uiSref to communicate with uiSrefActive[Equals]
33385               this.$$addStateInfo = function (newState, newParams) {
33386                 var state = $state.get(newState, stateContext($element));
33387
33388                 states.push({
33389                   state: state || { name: newState },
33390                   params: newParams
33391                 });
33392
33393                 update();
33394               };
33395
33396               $scope.$on('$stateChangeSuccess', update);
33397
33398               // Update route state
33399               function update() {
33400                 if (anyMatch()) {
33401                   $element.addClass(activeClass);
33402                 } else {
33403                   $element.removeClass(activeClass);
33404                 }
33405               }
33406
33407               function anyMatch() {
33408                 for (var i = 0; i < states.length; i++) {
33409                   if (isMatch(states[i].state, states[i].params)) {
33410                     return true;
33411                   }
33412                 }
33413                 return false;
33414               }
33415
33416               function isMatch(state, params) {
33417                 if (typeof $attrs.uiSrefActiveEq !== 'undefined') {
33418                   return $state.is(state.name, params);
33419                 } else {
33420                   return $state.includes(state.name, params);
33421                 }
33422               }
33423             }]
33424           };
33425         }
33426
33427         angular.module('ui.router.state')
33428           .directive('uiSref', $StateRefDirective)
33429           .directive('uiSrefActive', $StateRefActiveDirective)
33430           .directive('uiSrefActiveEq', $StateRefActiveDirective);
33431
33432         /**
33433          * @ngdoc filter
33434          * @name ui.router.state.filter:isState
33435          *
33436          * @requires ui.router.state.$state
33437          *
33438          * @description
33439          * Translates to {@link ui.router.state.$state#methods_is $state.is("stateName")}.
33440          */
33441         $IsStateFilter.$inject = ['$state'];
33442         function $IsStateFilter($state) {
33443           var isFilter = function (state) {
33444             return $state.is(state);
33445           };
33446           isFilter.$stateful = true;
33447           return isFilter;
33448         }
33449
33450         /**
33451          * @ngdoc filter
33452          * @name ui.router.state.filter:includedByState
33453          *
33454          * @requires ui.router.state.$state
33455          *
33456          * @description
33457          * Translates to {@link ui.router.state.$state#methods_includes $state.includes('fullOrPartialStateName')}.
33458          */
33459         $IncludedByStateFilter.$inject = ['$state'];
33460         function $IncludedByStateFilter($state) {
33461           var includesFilter = function (state) {
33462             return $state.includes(state);
33463           };
33464           includesFilter.$stateful = true;
33465           return  includesFilter;
33466         }
33467
33468         angular.module('ui.router.state')
33469           .filter('isState', $IsStateFilter)
33470           .filter('includedByState', $IncludedByStateFilter);
33471         })(window, window.angular);
33472
33473 /***/ },
33474 /* 4 */
33475 /***/ function(module, exports, __webpack_require__) {
33476
33477         __webpack_require__(5);
33478         module.exports = 'ngResource';
33479
33480
33481 /***/ },
33482 /* 5 */
33483 /***/ function(module, exports) {
33484
33485         /**
33486          * @license AngularJS v1.4.8
33487          * (c) 2010-2015 Google, Inc. http://angularjs.org
33488          * License: MIT
33489          */
33490         (function(window, angular, undefined) {'use strict';
33491
33492         var $resourceMinErr = angular.$$minErr('$resource');
33493
33494         // Helper functions and regex to lookup a dotted path on an object
33495         // stopping at undefined/null.  The path must be composed of ASCII
33496         // identifiers (just like $parse)
33497         var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;
33498
33499         function isValidDottedPath(path) {
33500           return (path != null && path !== '' && path !== 'hasOwnProperty' &&
33501               MEMBER_NAME_REGEX.test('.' + path));
33502         }
33503
33504         function lookupDottedPath(obj, path) {
33505           if (!isValidDottedPath(path)) {
33506             throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
33507           }
33508           var keys = path.split('.');
33509           for (var i = 0, ii = keys.length; i < ii && angular.isDefined(obj); i++) {
33510             var key = keys[i];
33511             obj = (obj !== null) ? obj[key] : undefined;
33512           }
33513           return obj;
33514         }
33515
33516         /**
33517          * Create a shallow copy of an object and clear other fields from the destination
33518          */
33519         function shallowClearAndCopy(src, dst) {
33520           dst = dst || {};
33521
33522           angular.forEach(dst, function(value, key) {
33523             delete dst[key];
33524           });
33525
33526           for (var key in src) {
33527             if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
33528               dst[key] = src[key];
33529             }
33530           }
33531
33532           return dst;
33533         }
33534
33535         /**
33536          * @ngdoc module
33537          * @name ngResource
33538          * @description
33539          *
33540          * # ngResource
33541          *
33542          * The `ngResource` module provides interaction support with RESTful services
33543          * via the $resource service.
33544          *
33545          *
33546          * <div doc-module-components="ngResource"></div>
33547          *
33548          * See {@link ngResource.$resource `$resource`} for usage.
33549          */
33550
33551         /**
33552          * @ngdoc service
33553          * @name $resource
33554          * @requires $http
33555          *
33556          * @description
33557          * A factory which creates a resource object that lets you interact with
33558          * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
33559          *
33560          * The returned resource object has action methods which provide high-level behaviors without
33561          * the need to interact with the low level {@link ng.$http $http} service.
33562          *
33563          * Requires the {@link ngResource `ngResource`} module to be installed.
33564          *
33565          * By default, trailing slashes will be stripped from the calculated URLs,
33566          * which can pose problems with server backends that do not expect that
33567          * behavior.  This can be disabled by configuring the `$resourceProvider` like
33568          * this:
33569          *
33570          * ```js
33571              app.config(['$resourceProvider', function($resourceProvider) {
33572                // Don't strip trailing slashes from calculated URLs
33573                $resourceProvider.defaults.stripTrailingSlashes = false;
33574              }]);
33575          * ```
33576          *
33577          * @param {string} url A parameterized URL template with parameters prefixed by `:` as in
33578          *   `/user/:username`. If you are using a URL with a port number (e.g.
33579          *   `http://example.com:8080/api`), it will be respected.
33580          *
33581          *   If you are using a url with a suffix, just add the suffix, like this:
33582          *   `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
33583          *   or even `$resource('http://example.com/resource/:resource_id.:format')`
33584          *   If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
33585          *   collapsed down to a single `.`.  If you need this sequence to appear and not collapse then you
33586          *   can escape it with `/\.`.
33587          *
33588          * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
33589          *   `actions` methods. If any of the parameter value is a function, it will be executed every time
33590          *   when a param value needs to be obtained for a request (unless the param was overridden).
33591          *
33592          *   Each key value in the parameter object is first bound to url template if present and then any
33593          *   excess keys are appended to the url search query after the `?`.
33594          *
33595          *   Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
33596          *   URL `/path/greet?salutation=Hello`.
33597          *
33598          *   If the parameter value is prefixed with `@` then the value for that parameter will be extracted
33599          *   from the corresponding property on the `data` object (provided when calling an action method).  For
33600          *   example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam`
33601          *   will be `data.someProp`.
33602          *
33603          * @param {Object.<Object>=} actions Hash with declaration of custom actions that should extend
33604          *   the default set of resource actions. The declaration should be created in the format of {@link
33605          *   ng.$http#usage $http.config}:
33606          *
33607          *       {action1: {method:?, params:?, isArray:?, headers:?, ...},
33608          *        action2: {method:?, params:?, isArray:?, headers:?, ...},
33609          *        ...}
33610          *
33611          *   Where:
33612          *
33613          *   - **`action`** – {string} – The name of action. This name becomes the name of the method on
33614          *     your resource object.
33615          *   - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
33616          *     `DELETE`, `JSONP`, etc).
33617          *   - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
33618          *     the parameter value is a function, it will be executed every time when a param value needs to
33619          *     be obtained for a request (unless the param was overridden).
33620          *   - **`url`** – {string} – action specific `url` override. The url templating is supported just
33621          *     like for the resource-level urls.
33622          *   - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
33623          *     see `returns` section.
33624          *   - **`transformRequest`** –
33625          *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
33626          *     transform function or an array of such functions. The transform function takes the http
33627          *     request body and headers and returns its transformed (typically serialized) version.
33628          *     By default, transformRequest will contain one function that checks if the request data is
33629          *     an object and serializes to using `angular.toJson`. To prevent this behavior, set
33630          *     `transformRequest` to an empty array: `transformRequest: []`
33631          *   - **`transformResponse`** –
33632          *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
33633          *     transform function or an array of such functions. The transform function takes the http
33634          *     response body and headers and returns its transformed (typically deserialized) version.
33635          *     By default, transformResponse will contain one function that checks if the response looks like
33636          *     a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
33637          *     `transformResponse` to an empty array: `transformResponse: []`
33638          *   - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
33639          *     GET request, otherwise if a cache instance built with
33640          *     {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
33641          *     caching.
33642          *   - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
33643          *     should abort the request when resolved.
33644          *   - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
33645          *     XHR object. See
33646          *     [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
33647          *     for more information.
33648          *   - **`responseType`** - `{string}` - see
33649          *     [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
33650          *   - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
33651          *     `response` and `responseError`. Both `response` and `responseError` interceptors get called
33652          *     with `http response` object. See {@link ng.$http $http interceptors}.
33653          *
33654          * @param {Object} options Hash with custom settings that should extend the
33655          *   default `$resourceProvider` behavior.  The only supported option is
33656          *
33657          *   Where:
33658          *
33659          *   - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
33660          *   slashes from any calculated URL will be stripped. (Defaults to true.)
33661          *
33662          * @returns {Object} A resource "class" object with methods for the default set of resource actions
33663          *   optionally extended with custom `actions`. The default set contains these actions:
33664          *   ```js
33665          *   { 'get':    {method:'GET'},
33666          *     'save':   {method:'POST'},
33667          *     'query':  {method:'GET', isArray:true},
33668          *     'remove': {method:'DELETE'},
33669          *     'delete': {method:'DELETE'} };
33670          *   ```
33671          *
33672          *   Calling these methods invoke an {@link ng.$http} with the specified http method,
33673          *   destination and parameters. When the data is returned from the server then the object is an
33674          *   instance of the resource class. The actions `save`, `remove` and `delete` are available on it
33675          *   as  methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
33676          *   read, update, delete) on server-side data like this:
33677          *   ```js
33678          *   var User = $resource('/user/:userId', {userId:'@id'});
33679          *   var user = User.get({userId:123}, function() {
33680          *     user.abc = true;
33681          *     user.$save();
33682          *   });
33683          *   ```
33684          *
33685          *   It is important to realize that invoking a $resource object method immediately returns an
33686          *   empty reference (object or array depending on `isArray`). Once the data is returned from the
33687          *   server the existing reference is populated with the actual data. This is a useful trick since
33688          *   usually the resource is assigned to a model which is then rendered by the view. Having an empty
33689          *   object results in no rendering, once the data arrives from the server then the object is
33690          *   populated with the data and the view automatically re-renders itself showing the new data. This
33691          *   means that in most cases one never has to write a callback function for the action methods.
33692          *
33693          *   The action methods on the class object or instance object can be invoked with the following
33694          *   parameters:
33695          *
33696          *   - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
33697          *   - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
33698          *   - non-GET instance actions:  `instance.$action([parameters], [success], [error])`
33699          *
33700          *
33701          *   Success callback is called with (value, responseHeaders) arguments, where the value is
33702          *   the populated resource instance or collection object. The error callback is called
33703          *   with (httpResponse) argument.
33704          *
33705          *   Class actions return empty instance (with additional properties below).
33706          *   Instance actions return promise of the action.
33707          *
33708          *   The Resource instances and collection have these additional properties:
33709          *
33710          *   - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
33711          *     instance or collection.
33712          *
33713          *     On success, the promise is resolved with the same resource instance or collection object,
33714          *     updated with data from server. This makes it easy to use in
33715          *     {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
33716          *     rendering until the resource(s) are loaded.
33717          *
33718          *     On failure, the promise is resolved with the {@link ng.$http http response} object, without
33719          *     the `resource` property.
33720          *
33721          *     If an interceptor object was provided, the promise will instead be resolved with the value
33722          *     returned by the interceptor.
33723          *
33724          *   - `$resolved`: `true` after first server interaction is completed (either with success or
33725          *      rejection), `false` before that. Knowing if the Resource has been resolved is useful in
33726          *      data-binding.
33727          *
33728          * @example
33729          *
33730          * # Credit card resource
33731          *
33732          * ```js
33733              // Define CreditCard class
33734              var CreditCard = $resource('/user/:userId/card/:cardId',
33735               {userId:123, cardId:'@id'}, {
33736                charge: {method:'POST', params:{charge:true}}
33737               });
33738
33739              // We can retrieve a collection from the server
33740              var cards = CreditCard.query(function() {
33741                // GET: /user/123/card
33742                // server returns: [ {id:456, number:'1234', name:'Smith'} ];
33743
33744                var card = cards[0];
33745                // each item is an instance of CreditCard
33746                expect(card instanceof CreditCard).toEqual(true);
33747                card.name = "J. Smith";
33748                // non GET methods are mapped onto the instances
33749                card.$save();
33750                // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
33751                // server returns: {id:456, number:'1234', name: 'J. Smith'};
33752
33753                // our custom method is mapped as well.
33754                card.$charge({amount:9.99});
33755                // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
33756              });
33757
33758              // we can create an instance as well
33759              var newCard = new CreditCard({number:'0123'});
33760              newCard.name = "Mike Smith";
33761              newCard.$save();
33762              // POST: /user/123/card {number:'0123', name:'Mike Smith'}
33763              // server returns: {id:789, number:'0123', name: 'Mike Smith'};
33764              expect(newCard.id).toEqual(789);
33765          * ```
33766          *
33767          * The object returned from this function execution is a resource "class" which has "static" method
33768          * for each action in the definition.
33769          *
33770          * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
33771          * `headers`.
33772          * When the data is returned from the server then the object is an instance of the resource type and
33773          * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
33774          * operations (create, read, update, delete) on server-side data.
33775
33776            ```js
33777              var User = $resource('/user/:userId', {userId:'@id'});
33778              User.get({userId:123}, function(user) {
33779                user.abc = true;
33780                user.$save();
33781              });
33782            ```
33783          *
33784          * It's worth noting that the success callback for `get`, `query` and other methods gets passed
33785          * in the response that came from the server as well as $http header getter function, so one
33786          * could rewrite the above example and get access to http headers as:
33787          *
33788            ```js
33789              var User = $resource('/user/:userId', {userId:'@id'});
33790              User.get({userId:123}, function(u, getResponseHeaders){
33791                u.abc = true;
33792                u.$save(function(u, putResponseHeaders) {
33793                  //u => saved user object
33794                  //putResponseHeaders => $http header getter
33795                });
33796              });
33797            ```
33798          *
33799          * You can also access the raw `$http` promise via the `$promise` property on the object returned
33800          *
33801            ```
33802              var User = $resource('/user/:userId', {userId:'@id'});
33803              User.get({userId:123})
33804                  .$promise.then(function(user) {
33805                    $scope.user = user;
33806                  });
33807            ```
33808
33809          * # Creating a custom 'PUT' request
33810          * In this example we create a custom method on our resource to make a PUT request
33811          * ```js
33812          *    var app = angular.module('app', ['ngResource', 'ngRoute']);
33813          *
33814          *    // Some APIs expect a PUT request in the format URL/object/ID
33815          *    // Here we are creating an 'update' method
33816          *    app.factory('Notes', ['$resource', function($resource) {
33817          *    return $resource('/notes/:id', null,
33818          *        {
33819          *            'update': { method:'PUT' }
33820          *        });
33821          *    }]);
33822          *
33823          *    // In our controller we get the ID from the URL using ngRoute and $routeParams
33824          *    // We pass in $routeParams and our Notes factory along with $scope
33825          *    app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
33826                                               function($scope, $routeParams, Notes) {
33827          *    // First get a note object from the factory
33828          *    var note = Notes.get({ id:$routeParams.id });
33829          *    $id = note.id;
33830          *
33831          *    // Now call update passing in the ID first then the object you are updating
33832          *    Notes.update({ id:$id }, note);
33833          *
33834          *    // This will PUT /notes/ID with the note object in the request payload
33835          *    }]);
33836          * ```
33837          */
33838         angular.module('ngResource', ['ng']).
33839           provider('$resource', function() {
33840             var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
33841             var provider = this;
33842
33843             this.defaults = {
33844               // Strip slashes by default
33845               stripTrailingSlashes: true,
33846
33847               // Default actions configuration
33848               actions: {
33849                 'get': {method: 'GET'},
33850                 'save': {method: 'POST'},
33851                 'query': {method: 'GET', isArray: true},
33852                 'remove': {method: 'DELETE'},
33853                 'delete': {method: 'DELETE'}
33854               }
33855             };
33856
33857             this.$get = ['$http', '$q', function($http, $q) {
33858
33859               var noop = angular.noop,
33860                 forEach = angular.forEach,
33861                 extend = angular.extend,
33862                 copy = angular.copy,
33863                 isFunction = angular.isFunction;
33864
33865               /**
33866                * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
33867                * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
33868                * (pchar) allowed in path segments:
33869                *    segment       = *pchar
33870                *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
33871                *    pct-encoded   = "%" HEXDIG HEXDIG
33872                *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
33873                *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
33874                *                     / "*" / "+" / "," / ";" / "="
33875                */
33876               function encodeUriSegment(val) {
33877                 return encodeUriQuery(val, true).
33878                   replace(/%26/gi, '&').
33879                   replace(/%3D/gi, '=').
33880                   replace(/%2B/gi, '+');
33881               }
33882
33883
33884               /**
33885                * This method is intended for encoding *key* or *value* parts of query component. We need a
33886                * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
33887                * have to be encoded per http://tools.ietf.org/html/rfc3986:
33888                *    query       = *( pchar / "/" / "?" )
33889                *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
33890                *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
33891                *    pct-encoded   = "%" HEXDIG HEXDIG
33892                *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
33893                *                     / "*" / "+" / "," / ";" / "="
33894                */
33895               function encodeUriQuery(val, pctEncodeSpaces) {
33896                 return encodeURIComponent(val).
33897                   replace(/%40/gi, '@').
33898                   replace(/%3A/gi, ':').
33899                   replace(/%24/g, '$').
33900                   replace(/%2C/gi, ',').
33901                   replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
33902               }
33903
33904               function Route(template, defaults) {
33905                 this.template = template;
33906                 this.defaults = extend({}, provider.defaults, defaults);
33907                 this.urlParams = {};
33908               }
33909
33910               Route.prototype = {
33911                 setUrlParams: function(config, params, actionUrl) {
33912                   var self = this,
33913                     url = actionUrl || self.template,
33914                     val,
33915                     encodedVal,
33916                     protocolAndDomain = '';
33917
33918                   var urlParams = self.urlParams = {};
33919                   forEach(url.split(/\W/), function(param) {
33920                     if (param === 'hasOwnProperty') {
33921                       throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
33922                     }
33923                     if (!(new RegExp("^\\d+$").test(param)) && param &&
33924                       (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
33925                       urlParams[param] = true;
33926                     }
33927                   });
33928                   url = url.replace(/\\:/g, ':');
33929                   url = url.replace(PROTOCOL_AND_DOMAIN_REGEX, function(match) {
33930                     protocolAndDomain = match;
33931                     return '';
33932                   });
33933
33934                   params = params || {};
33935                   forEach(self.urlParams, function(_, urlParam) {
33936                     val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
33937                     if (angular.isDefined(val) && val !== null) {
33938                       encodedVal = encodeUriSegment(val);
33939                       url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
33940                         return encodedVal + p1;
33941                       });
33942                     } else {
33943                       url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
33944                           leadingSlashes, tail) {
33945                         if (tail.charAt(0) == '/') {
33946                           return tail;
33947                         } else {
33948                           return leadingSlashes + tail;
33949                         }
33950                       });
33951                     }
33952                   });
33953
33954                   // strip trailing slashes and set the url (unless this behavior is specifically disabled)
33955                   if (self.defaults.stripTrailingSlashes) {
33956                     url = url.replace(/\/+$/, '') || '/';
33957                   }
33958
33959                   // then replace collapse `/.` if found in the last URL path segment before the query
33960                   // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
33961                   url = url.replace(/\/\.(?=\w+($|\?))/, '.');
33962                   // replace escaped `/\.` with `/.`
33963                   config.url = protocolAndDomain + url.replace(/\/\\\./, '/.');
33964
33965
33966                   // set params - delegate param encoding to $http
33967                   forEach(params, function(value, key) {
33968                     if (!self.urlParams[key]) {
33969                       config.params = config.params || {};
33970                       config.params[key] = value;
33971                     }
33972                   });
33973                 }
33974               };
33975
33976
33977               function resourceFactory(url, paramDefaults, actions, options) {
33978                 var route = new Route(url, options);
33979
33980                 actions = extend({}, provider.defaults.actions, actions);
33981
33982                 function extractParams(data, actionParams) {
33983                   var ids = {};
33984                   actionParams = extend({}, paramDefaults, actionParams);
33985                   forEach(actionParams, function(value, key) {
33986                     if (isFunction(value)) { value = value(); }
33987                     ids[key] = value && value.charAt && value.charAt(0) == '@' ?
33988                       lookupDottedPath(data, value.substr(1)) : value;
33989                   });
33990                   return ids;
33991                 }
33992
33993                 function defaultResponseInterceptor(response) {
33994                   return response.resource;
33995                 }
33996
33997                 function Resource(value) {
33998                   shallowClearAndCopy(value || {}, this);
33999                 }
34000
34001                 Resource.prototype.toJSON = function() {
34002                   var data = extend({}, this);
34003                   delete data.$promise;
34004                   delete data.$resolved;
34005                   return data;
34006                 };
34007
34008                 forEach(actions, function(action, name) {
34009                   var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
34010
34011                   Resource[name] = function(a1, a2, a3, a4) {
34012                     var params = {}, data, success, error;
34013
34014                     /* jshint -W086 */ /* (purposefully fall through case statements) */
34015                     switch (arguments.length) {
34016                       case 4:
34017                         error = a4;
34018                         success = a3;
34019                       //fallthrough
34020                       case 3:
34021                       case 2:
34022                         if (isFunction(a2)) {
34023                           if (isFunction(a1)) {
34024                             success = a1;
34025                             error = a2;
34026                             break;
34027                           }
34028
34029                           success = a2;
34030                           error = a3;
34031                           //fallthrough
34032                         } else {
34033                           params = a1;
34034                           data = a2;
34035                           success = a3;
34036                           break;
34037                         }
34038                       case 1:
34039                         if (isFunction(a1)) success = a1;
34040                         else if (hasBody) data = a1;
34041                         else params = a1;
34042                         break;
34043                       case 0: break;
34044                       default:
34045                         throw $resourceMinErr('badargs',
34046                           "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
34047                           arguments.length);
34048                     }
34049                     /* jshint +W086 */ /* (purposefully fall through case statements) */
34050
34051                     var isInstanceCall = this instanceof Resource;
34052                     var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
34053                     var httpConfig = {};
34054                     var responseInterceptor = action.interceptor && action.interceptor.response ||
34055                       defaultResponseInterceptor;
34056                     var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
34057                       undefined;
34058
34059                     forEach(action, function(value, key) {
34060                       switch (key) {
34061                         default:
34062                           httpConfig[key] = copy(value);
34063                           break;
34064                         case 'params':
34065                         case 'isArray':
34066                         case 'interceptor':
34067                           break;
34068                         case 'timeout':
34069                           httpConfig[key] = value;
34070                           break;
34071                       }
34072                     });
34073
34074                     if (hasBody) httpConfig.data = data;
34075                     route.setUrlParams(httpConfig,
34076                       extend({}, extractParams(data, action.params || {}), params),
34077                       action.url);
34078
34079                     var promise = $http(httpConfig).then(function(response) {
34080                       var data = response.data,
34081                         promise = value.$promise;
34082
34083                       if (data) {
34084                         // Need to convert action.isArray to boolean in case it is undefined
34085                         // jshint -W018
34086                         if (angular.isArray(data) !== (!!action.isArray)) {
34087                           throw $resourceMinErr('badcfg',
34088                               'Error in resource configuration for action `{0}`. Expected response to ' +
34089                               'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object',
34090                             angular.isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
34091                         }
34092                         // jshint +W018
34093                         if (action.isArray) {
34094                           value.length = 0;
34095                           forEach(data, function(item) {
34096                             if (typeof item === "object") {
34097                               value.push(new Resource(item));
34098                             } else {
34099                               // Valid JSON values may be string literals, and these should not be converted
34100                               // into objects. These items will not have access to the Resource prototype
34101                               // methods, but unfortunately there
34102                               value.push(item);
34103                             }
34104                           });
34105                         } else {
34106                           shallowClearAndCopy(data, value);
34107                           value.$promise = promise;
34108                         }
34109                       }
34110
34111                       value.$resolved = true;
34112
34113                       response.resource = value;
34114
34115                       return response;
34116                     }, function(response) {
34117                       value.$resolved = true;
34118
34119                       (error || noop)(response);
34120
34121                       return $q.reject(response);
34122                     });
34123
34124                     promise = promise.then(
34125                       function(response) {
34126                         var value = responseInterceptor(response);
34127                         (success || noop)(value, response.headers);
34128                         return value;
34129                       },
34130                       responseErrorInterceptor);
34131
34132                     if (!isInstanceCall) {
34133                       // we are creating instance / collection
34134                       // - set the initial promise
34135                       // - return the instance / collection
34136                       value.$promise = promise;
34137                       value.$resolved = false;
34138
34139                       return value;
34140                     }
34141
34142                     // instance call
34143                     return promise;
34144                   };
34145
34146
34147                   Resource.prototype['$' + name] = function(params, success, error) {
34148                     if (isFunction(params)) {
34149                       error = success; success = params; params = {};
34150                     }
34151                     var result = Resource[name].call(this, params, this, success, error);
34152                     return result.$promise || result;
34153                   };
34154                 });
34155
34156                 Resource.bind = function(additionalParamDefaults) {
34157                   return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
34158                 };
34159
34160                 return Resource;
34161               }
34162
34163               return resourceFactory;
34164             }];
34165           });
34166
34167
34168         })(window, window.angular);
34169
34170
34171 /***/ },
34172 /* 6 */
34173 /***/ function(module, exports, __webpack_require__) {
34174
34175         __webpack_require__(7);
34176
34177         module.exports = 'ui.bootstrap';
34178
34179
34180 /***/ },
34181 /* 7 */
34182 /***/ function(module, exports) {
34183
34184         /*
34185          * angular-ui-bootstrap
34186          * http://angular-ui.github.io/bootstrap/
34187
34188          * Version: 1.0.0 - 2016-01-08
34189          * License: MIT
34190          */
34191         angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.isClass","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.debounce","ui.bootstrap.dropdown","ui.bootstrap.stackedMap","ui.bootstrap.modal","ui.bootstrap.paging","ui.bootstrap.pager","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]);
34192         angular.module("ui.bootstrap.tpls", ["uib/template/accordion/accordion-group.html","uib/template/accordion/accordion.html","uib/template/alert/alert.html","uib/template/carousel/carousel.html","uib/template/carousel/slide.html","uib/template/datepicker/datepicker.html","uib/template/datepicker/day.html","uib/template/datepicker/month.html","uib/template/datepicker/popup.html","uib/template/datepicker/year.html","uib/template/modal/backdrop.html","uib/template/modal/window.html","uib/template/pager/pager.html","uib/template/pagination/pagination.html","uib/template/tooltip/tooltip-html-popup.html","uib/template/tooltip/tooltip-popup.html","uib/template/tooltip/tooltip-template-popup.html","uib/template/popover/popover-html.html","uib/template/popover/popover-template.html","uib/template/popover/popover.html","uib/template/progressbar/bar.html","uib/template/progressbar/progress.html","uib/template/progressbar/progressbar.html","uib/template/rating/rating.html","uib/template/tabs/tab.html","uib/template/tabs/tabset.html","uib/template/timepicker/timepicker.html","uib/template/typeahead/typeahead-match.html","uib/template/typeahead/typeahead-popup.html"]);
34193         angular.module('ui.bootstrap.collapse', [])
34194
34195           .directive('uibCollapse', ['$animate', '$injector', function($animate, $injector) {
34196             var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') : null;
34197             return {
34198               link: function(scope, element, attrs) {
34199                 if (!scope.$eval(attrs.uibCollapse)) {
34200                   element.addClass('in')
34201                     .addClass('collapse')
34202                     .css({height: 'auto'});
34203                 }
34204
34205                 function expand() {
34206                   element.removeClass('collapse')
34207                     .addClass('collapsing')
34208                     .attr('aria-expanded', true)
34209                     .attr('aria-hidden', false);
34210
34211                   if ($animateCss) {
34212                     $animateCss(element, {
34213                       addClass: 'in',
34214                       easing: 'ease',
34215                       to: { height: element[0].scrollHeight + 'px' }
34216                     }).start()['finally'](expandDone);
34217                   } else {
34218                     $animate.addClass(element, 'in', {
34219                       to: { height: element[0].scrollHeight + 'px' }
34220                     }).then(expandDone);
34221                   }
34222                 }
34223
34224                 function expandDone() {
34225                   element.removeClass('collapsing')
34226                     .addClass('collapse')
34227                     .css({height: 'auto'});
34228                 }
34229
34230                 function collapse() {
34231                   if (!element.hasClass('collapse') && !element.hasClass('in')) {
34232                     return collapseDone();
34233                   }
34234
34235                   element
34236                     // IMPORTANT: The height must be set before adding "collapsing" class.
34237                     // Otherwise, the browser attempts to animate from height 0 (in
34238                     // collapsing class) to the given height here.
34239                     .css({height: element[0].scrollHeight + 'px'})
34240                     // initially all panel collapse have the collapse class, this removal
34241                     // prevents the animation from jumping to collapsed state
34242                     .removeClass('collapse')
34243                     .addClass('collapsing')
34244                     .attr('aria-expanded', false)
34245                     .attr('aria-hidden', true);
34246
34247                   if ($animateCss) {
34248                     $animateCss(element, {
34249                       removeClass: 'in',
34250                       to: {height: '0'}
34251                     }).start()['finally'](collapseDone);
34252                   } else {
34253                     $animate.removeClass(element, 'in', {
34254                       to: {height: '0'}
34255                     }).then(collapseDone);
34256                   }
34257                 }
34258
34259                 function collapseDone() {
34260                   element.css({height: '0'}); // Required so that collapse works when animation is disabled
34261                   element.removeClass('collapsing')
34262                     .addClass('collapse');
34263                 }
34264
34265                 scope.$watch(attrs.uibCollapse, function(shouldCollapse) {
34266                   if (shouldCollapse) {
34267                     collapse();
34268                   } else {
34269                     expand();
34270                   }
34271                 });
34272               }
34273             };
34274           }]);
34275
34276         angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
34277
34278         .constant('uibAccordionConfig', {
34279           closeOthers: true
34280         })
34281
34282         .controller('UibAccordionController', ['$scope', '$attrs', 'uibAccordionConfig', function($scope, $attrs, accordionConfig) {
34283           // This array keeps track of the accordion groups
34284           this.groups = [];
34285
34286           // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
34287           this.closeOthers = function(openGroup) {
34288             var closeOthers = angular.isDefined($attrs.closeOthers) ?
34289               $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
34290             if (closeOthers) {
34291               angular.forEach(this.groups, function(group) {
34292                 if (group !== openGroup) {
34293                   group.isOpen = false;
34294                 }
34295               });
34296             }
34297           };
34298
34299           // This is called from the accordion-group directive to add itself to the accordion
34300           this.addGroup = function(groupScope) {
34301             var that = this;
34302             this.groups.push(groupScope);
34303
34304             groupScope.$on('$destroy', function(event) {
34305               that.removeGroup(groupScope);
34306             });
34307           };
34308
34309           // This is called from the accordion-group directive when to remove itself
34310           this.removeGroup = function(group) {
34311             var index = this.groups.indexOf(group);
34312             if (index !== -1) {
34313               this.groups.splice(index, 1);
34314             }
34315           };
34316         }])
34317
34318         // The accordion directive simply sets up the directive controller
34319         // and adds an accordion CSS class to itself element.
34320         .directive('uibAccordion', function() {
34321           return {
34322             controller: 'UibAccordionController',
34323             controllerAs: 'accordion',
34324             transclude: true,
34325             templateUrl: function(element, attrs) {
34326               return attrs.templateUrl || 'uib/template/accordion/accordion.html';
34327             }
34328           };
34329         })
34330
34331         // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
34332         .directive('uibAccordionGroup', function() {
34333           return {
34334             require: '^uibAccordion',         // We need this directive to be inside an accordion
34335             transclude: true,              // It transcludes the contents of the directive into the template
34336             replace: true,                // The element containing the directive will be replaced with the template
34337             templateUrl: function(element, attrs) {
34338               return attrs.templateUrl || 'uib/template/accordion/accordion-group.html';
34339             },
34340             scope: {
34341               heading: '@',               // Interpolate the heading attribute onto this scope
34342               isOpen: '=?',
34343               isDisabled: '=?'
34344             },
34345             controller: function() {
34346               this.setHeading = function(element) {
34347                 this.heading = element;
34348               };
34349             },
34350             link: function(scope, element, attrs, accordionCtrl) {
34351               accordionCtrl.addGroup(scope);
34352
34353               scope.openClass = attrs.openClass || 'panel-open';
34354               scope.panelClass = attrs.panelClass || 'panel-default';
34355               scope.$watch('isOpen', function(value) {
34356                 element.toggleClass(scope.openClass, !!value);
34357                 if (value) {
34358                   accordionCtrl.closeOthers(scope);
34359                 }
34360               });
34361
34362               scope.toggleOpen = function($event) {
34363                 if (!scope.isDisabled) {
34364                   if (!$event || $event.which === 32) {
34365                     scope.isOpen = !scope.isOpen;
34366                   }
34367                 }
34368               };
34369             }
34370           };
34371         })
34372
34373         // Use accordion-heading below an accordion-group to provide a heading containing HTML
34374         .directive('uibAccordionHeading', function() {
34375           return {
34376             transclude: true,   // Grab the contents to be used as the heading
34377             template: '',       // In effect remove this element!
34378             replace: true,
34379             require: '^uibAccordionGroup',
34380             link: function(scope, element, attrs, accordionGroupCtrl, transclude) {
34381               // Pass the heading to the accordion-group controller
34382               // so that it can be transcluded into the right place in the template
34383               // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
34384               accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
34385             }
34386           };
34387         })
34388
34389         // Use in the accordion-group template to indicate where you want the heading to be transcluded
34390         // You must provide the property on the accordion-group controller that will hold the transcluded element
34391         .directive('uibAccordionTransclude', function() {
34392           return {
34393             require: '^uibAccordionGroup',
34394             link: function(scope, element, attrs, controller) {
34395               scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) {
34396                 if (heading) {
34397                   element.find('span').html('');
34398                   element.find('span').append(heading);
34399                 }
34400               });
34401             }
34402           };
34403         });
34404
34405         angular.module('ui.bootstrap.alert', [])
34406
34407         .controller('UibAlertController', ['$scope', '$attrs', '$interpolate', '$timeout', function($scope, $attrs, $interpolate, $timeout) {
34408           $scope.closeable = !!$attrs.close;
34409
34410           var dismissOnTimeout = angular.isDefined($attrs.dismissOnTimeout) ?
34411             $interpolate($attrs.dismissOnTimeout)($scope.$parent) : null;
34412
34413           if (dismissOnTimeout) {
34414             $timeout(function() {
34415               $scope.close();
34416             }, parseInt(dismissOnTimeout, 10));
34417           }
34418         }])
34419
34420         .directive('uibAlert', function() {
34421           return {
34422             controller: 'UibAlertController',
34423             controllerAs: 'alert',
34424             templateUrl: function(element, attrs) {
34425               return attrs.templateUrl || 'uib/template/alert/alert.html';
34426             },
34427             transclude: true,
34428             replace: true,
34429             scope: {
34430               type: '@',
34431               close: '&'
34432             }
34433           };
34434         });
34435
34436         angular.module('ui.bootstrap.buttons', [])
34437
34438         .constant('uibButtonConfig', {
34439           activeClass: 'active',
34440           toggleEvent: 'click'
34441         })
34442
34443         .controller('UibButtonsController', ['uibButtonConfig', function(buttonConfig) {
34444           this.activeClass = buttonConfig.activeClass || 'active';
34445           this.toggleEvent = buttonConfig.toggleEvent || 'click';
34446         }])
34447
34448         .directive('uibBtnRadio', ['$parse', function($parse) {
34449           return {
34450             require: ['uibBtnRadio', 'ngModel'],
34451             controller: 'UibButtonsController',
34452             controllerAs: 'buttons',
34453             link: function(scope, element, attrs, ctrls) {
34454               var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
34455               var uncheckableExpr = $parse(attrs.uibUncheckable);
34456
34457               element.find('input').css({display: 'none'});
34458
34459               //model -> UI
34460               ngModelCtrl.$render = function() {
34461                 element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.uibBtnRadio)));
34462               };
34463
34464               //ui->model
34465               element.on(buttonsCtrl.toggleEvent, function() {
34466                 if (attrs.disabled) {
34467                   return;
34468                 }
34469
34470                 var isActive = element.hasClass(buttonsCtrl.activeClass);
34471
34472                 if (!isActive || angular.isDefined(attrs.uncheckable)) {
34473                   scope.$apply(function() {
34474                     ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.uibBtnRadio));
34475                     ngModelCtrl.$render();
34476                   });
34477                 }
34478               });
34479
34480               if (attrs.uibUncheckable) {
34481                 scope.$watch(uncheckableExpr, function(uncheckable) {
34482                   attrs.$set('uncheckable', uncheckable ? '' : null);
34483                 });
34484               }
34485             }
34486           };
34487         }])
34488
34489         .directive('uibBtnCheckbox', function() {
34490           return {
34491             require: ['uibBtnCheckbox', 'ngModel'],
34492             controller: 'UibButtonsController',
34493             controllerAs: 'button',
34494             link: function(scope, element, attrs, ctrls) {
34495               var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
34496
34497               element.find('input').css({display: 'none'});
34498
34499               function getTrueValue() {
34500                 return getCheckboxValue(attrs.btnCheckboxTrue, true);
34501               }
34502
34503               function getFalseValue() {
34504                 return getCheckboxValue(attrs.btnCheckboxFalse, false);
34505               }
34506
34507               function getCheckboxValue(attribute, defaultValue) {
34508                 return angular.isDefined(attribute) ? scope.$eval(attribute) : defaultValue;
34509               }
34510
34511               //model -> UI
34512               ngModelCtrl.$render = function() {
34513                 element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
34514               };
34515
34516               //ui->model
34517               element.on(buttonsCtrl.toggleEvent, function() {
34518                 if (attrs.disabled) {
34519                   return;
34520                 }
34521
34522                 scope.$apply(function() {
34523                   ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue());
34524                   ngModelCtrl.$render();
34525                 });
34526               });
34527             }
34528           };
34529         });
34530
34531         angular.module('ui.bootstrap.carousel', [])
34532
34533         .controller('UibCarouselController', ['$scope', '$element', '$interval', '$timeout', '$animate', function($scope, $element, $interval, $timeout, $animate) {
34534           var self = this,
34535             slides = self.slides = $scope.slides = [],
34536             SLIDE_DIRECTION = 'uib-slideDirection',
34537             currentIndex = -1,
34538             currentInterval, isPlaying, bufferedTransitions = [];
34539           self.currentSlide = null;
34540
34541           var destroyed = false;
34542
34543           self.addSlide = function(slide, element) {
34544             slide.$element = element;
34545             slides.push(slide);
34546             //if this is the first slide or the slide is set to active, select it
34547             if (slides.length === 1 || slide.active) {
34548               if ($scope.$currentTransition) {
34549                 $scope.$currentTransition = null;
34550               }
34551
34552               self.select(slides[slides.length - 1]);
34553               if (slides.length === 1) {
34554                 $scope.play();
34555               }
34556             } else {
34557               slide.active = false;
34558             }
34559           };
34560
34561           self.getCurrentIndex = function() {
34562             if (self.currentSlide && angular.isDefined(self.currentSlide.index)) {
34563               return +self.currentSlide.index;
34564             }
34565             return currentIndex;
34566           };
34567
34568           self.next = $scope.next = function() {
34569             var newIndex = (self.getCurrentIndex() + 1) % slides.length;
34570
34571             if (newIndex === 0 && $scope.noWrap()) {
34572               $scope.pause();
34573               return;
34574             }
34575
34576             return self.select(getSlideByIndex(newIndex), 'next');
34577           };
34578
34579           self.prev = $scope.prev = function() {
34580             var newIndex = self.getCurrentIndex() - 1 < 0 ? slides.length - 1 : self.getCurrentIndex() - 1;
34581
34582             if ($scope.noWrap() && newIndex === slides.length - 1) {
34583               $scope.pause();
34584               return;
34585             }
34586
34587             return self.select(getSlideByIndex(newIndex), 'prev');
34588           };
34589
34590           self.removeSlide = function(slide) {
34591             if (angular.isDefined(slide.index)) {
34592               slides.sort(function(a, b) {
34593                 return +a.index > +b.index;
34594               });
34595             }
34596
34597             var bufferedIndex = bufferedTransitions.indexOf(slide);
34598             if (bufferedIndex !== -1) {
34599               bufferedTransitions.splice(bufferedIndex, 1);
34600             }
34601             //get the index of the slide inside the carousel
34602             var index = slides.indexOf(slide);
34603             slides.splice(index, 1);
34604             $timeout(function() {
34605               if (slides.length > 0 && slide.active) {
34606                 if (index >= slides.length) {
34607                   self.select(slides[index - 1]);
34608                 } else {
34609                   self.select(slides[index]);
34610                 }
34611               } else if (currentIndex > index) {
34612                 currentIndex--;
34613               }
34614             });
34615
34616             //clean the currentSlide when no more slide
34617             if (slides.length === 0) {
34618               self.currentSlide = null;
34619               clearBufferedTransitions();
34620             }
34621           };
34622
34623           /* direction: "prev" or "next" */
34624           self.select = $scope.select = function(nextSlide, direction) {
34625             var nextIndex = $scope.indexOfSlide(nextSlide);
34626             //Decide direction if it's not given
34627             if (direction === undefined) {
34628               direction = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
34629             }
34630             //Prevent this user-triggered transition from occurring if there is already one in progress
34631             if (nextSlide && nextSlide !== self.currentSlide && !$scope.$currentTransition) {
34632               goNext(nextSlide, nextIndex, direction);
34633             } else if (nextSlide && nextSlide !== self.currentSlide && $scope.$currentTransition) {
34634               bufferedTransitions.push(nextSlide);
34635             }
34636           };
34637
34638           /* Allow outside people to call indexOf on slides array */
34639           $scope.indexOfSlide = function(slide) {
34640             return angular.isDefined(slide.index) ? +slide.index : slides.indexOf(slide);
34641           };
34642
34643           $scope.isActive = function(slide) {
34644             return self.currentSlide === slide;
34645           };
34646
34647           $scope.pause = function() {
34648             if (!$scope.noPause) {
34649               isPlaying = false;
34650               resetTimer();
34651             }
34652           };
34653
34654           $scope.play = function() {
34655             if (!isPlaying) {
34656               isPlaying = true;
34657               restartTimer();
34658             }
34659           };
34660
34661           $scope.$on('$destroy', function() {
34662             destroyed = true;
34663             resetTimer();
34664           });
34665
34666           $scope.$watch('noTransition', function(noTransition) {
34667             $animate.enabled($element, !noTransition);
34668           });
34669
34670           $scope.$watch('interval', restartTimer);
34671
34672           $scope.$watchCollection('slides', resetTransition);
34673
34674           function clearBufferedTransitions() {
34675             while (bufferedTransitions.length) {
34676               bufferedTransitions.shift();
34677             }
34678           }
34679
34680           function getSlideByIndex(index) {
34681             if (angular.isUndefined(slides[index].index)) {
34682               return slides[index];
34683             }
34684             for (var i = 0, l = slides.length; i < l; ++i) {
34685               if (slides[i].index === index) {
34686                 return slides[i];
34687               }
34688             }
34689           }
34690
34691           function goNext(slide, index, direction) {
34692             if (destroyed) { return; }
34693
34694             angular.extend(slide, {direction: direction, active: true});
34695             angular.extend(self.currentSlide || {}, {direction: direction, active: false});
34696             if ($animate.enabled($element) && !$scope.$currentTransition &&
34697               slide.$element && self.slides.length > 1) {
34698               slide.$element.data(SLIDE_DIRECTION, slide.direction);
34699               if (self.currentSlide && self.currentSlide.$element) {
34700                 self.currentSlide.$element.data(SLIDE_DIRECTION, slide.direction);
34701               }
34702
34703               $scope.$currentTransition = true;
34704               $animate.on('addClass', slide.$element, function(element, phase) {
34705                 if (phase === 'close') {
34706                   $scope.$currentTransition = null;
34707                   $animate.off('addClass', element);
34708                   if (bufferedTransitions.length) {
34709                     var nextSlide = bufferedTransitions.pop();
34710                     var nextIndex = $scope.indexOfSlide(nextSlide);
34711                     var nextDirection = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
34712                     clearBufferedTransitions();
34713
34714                     goNext(nextSlide, nextIndex, nextDirection);
34715                   }
34716                 }
34717               });
34718             }
34719
34720             self.currentSlide = slide;
34721             currentIndex = index;
34722
34723             //every time you change slides, reset the timer
34724             restartTimer();
34725           }
34726
34727           function resetTimer() {
34728             if (currentInterval) {
34729               $interval.cancel(currentInterval);
34730               currentInterval = null;
34731             }
34732           }
34733
34734           function resetTransition(slides) {
34735             if (!slides.length) {
34736               $scope.$currentTransition = null;
34737               clearBufferedTransitions();
34738             }
34739           }
34740
34741           function restartTimer() {
34742             resetTimer();
34743             var interval = +$scope.interval;
34744             if (!isNaN(interval) && interval > 0) {
34745               currentInterval = $interval(timerFn, interval);
34746             }
34747           }
34748
34749           function timerFn() {
34750             var interval = +$scope.interval;
34751             if (isPlaying && !isNaN(interval) && interval > 0 && slides.length) {
34752               $scope.next();
34753             } else {
34754               $scope.pause();
34755             }
34756           }
34757         }])
34758
34759         .directive('uibCarousel', function() {
34760           return {
34761             transclude: true,
34762             replace: true,
34763             controller: 'UibCarouselController',
34764             controllerAs: 'carousel',
34765             templateUrl: function(element, attrs) {
34766               return attrs.templateUrl || 'uib/template/carousel/carousel.html';
34767             },
34768             scope: {
34769               interval: '=',
34770               noTransition: '=',
34771               noPause: '=',
34772               noWrap: '&'
34773             }
34774           };
34775         })
34776
34777         .directive('uibSlide', function() {
34778           return {
34779             require: '^uibCarousel',
34780             transclude: true,
34781             replace: true,
34782             templateUrl: function(element, attrs) {
34783               return attrs.templateUrl || 'uib/template/carousel/slide.html';
34784             },
34785             scope: {
34786               active: '=?',
34787               actual: '=?',
34788               index: '=?'
34789             },
34790             link: function (scope, element, attrs, carouselCtrl) {
34791               carouselCtrl.addSlide(scope, element);
34792               //when the scope is destroyed then remove the slide from the current slides array
34793               scope.$on('$destroy', function() {
34794                 carouselCtrl.removeSlide(scope);
34795               });
34796
34797               scope.$watch('active', function(active) {
34798                 if (active) {
34799                   carouselCtrl.select(scope);
34800                 }
34801               });
34802             }
34803           };
34804         })
34805
34806         .animation('.item', ['$animateCss',
34807         function($animateCss) {
34808           var SLIDE_DIRECTION = 'uib-slideDirection';
34809
34810           function removeClass(element, className, callback) {
34811             element.removeClass(className);
34812             if (callback) {
34813               callback();
34814             }
34815           }
34816
34817           return {
34818             beforeAddClass: function(element, className, done) {
34819               if (className === 'active') {
34820                 var stopped = false;
34821                 var direction = element.data(SLIDE_DIRECTION);
34822                 var directionClass = direction === 'next' ? 'left' : 'right';
34823                 var removeClassFn = removeClass.bind(this, element,
34824                   directionClass + ' ' + direction, done);
34825                 element.addClass(direction);
34826
34827                 $animateCss(element, {addClass: directionClass})
34828                   .start()
34829                   .done(removeClassFn);
34830
34831                 return function() {
34832                   stopped = true;
34833                 };
34834               }
34835               done();
34836             },
34837             beforeRemoveClass: function (element, className, done) {
34838               if (className === 'active') {
34839                 var stopped = false;
34840                 var direction = element.data(SLIDE_DIRECTION);
34841                 var directionClass = direction === 'next' ? 'left' : 'right';
34842                 var removeClassFn = removeClass.bind(this, element, directionClass, done);
34843
34844                 $animateCss(element, {addClass: directionClass})
34845                   .start()
34846                   .done(removeClassFn);
34847
34848                 return function() {
34849                   stopped = true;
34850                 };
34851               }
34852               done();
34853             }
34854           };
34855         }]);
34856
34857         angular.module('ui.bootstrap.dateparser', [])
34858
34859         .service('uibDateParser', ['$log', '$locale', 'orderByFilter', function($log, $locale, orderByFilter) {
34860           // Pulled from https://github.com/mbostock/d3/blob/master/src/format/requote.js
34861           var SPECIAL_CHARACTERS_REGEXP = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
34862
34863           var localeId;
34864           var formatCodeToRegex;
34865
34866           this.init = function() {
34867             localeId = $locale.id;
34868
34869             this.parsers = {};
34870
34871             formatCodeToRegex = [
34872               {
34873                 key: 'yyyy',
34874                 regex: '\\d{4}',
34875                 apply: function(value) { this.year = +value; }
34876               },
34877               {
34878                 key: 'yy',
34879                 regex: '\\d{2}',
34880                 apply: function(value) { this.year = +value + 2000; }
34881               },
34882               {
34883                 key: 'y',
34884                 regex: '\\d{1,4}',
34885                 apply: function(value) { this.year = +value; }
34886               },
34887               {
34888                 key: 'M!',
34889                 regex: '0?[1-9]|1[0-2]',
34890                 apply: function(value) { this.month = value - 1; }
34891               },
34892               {
34893                 key: 'MMMM',
34894                 regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
34895                 apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); }
34896               },
34897               {
34898                 key: 'MMM',
34899                 regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
34900                 apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); }
34901               },
34902               {
34903                 key: 'MM',
34904                 regex: '0[1-9]|1[0-2]',
34905                 apply: function(value) { this.month = value - 1; }
34906               },
34907               {
34908                 key: 'M',
34909                 regex: '[1-9]|1[0-2]',
34910                 apply: function(value) { this.month = value - 1; }
34911               },
34912               {
34913                 key: 'd!',
34914                 regex: '[0-2]?[0-9]{1}|3[0-1]{1}',
34915                 apply: function(value) { this.date = +value; }
34916               },
34917               {
34918                 key: 'dd',
34919                 regex: '[0-2][0-9]{1}|3[0-1]{1}',
34920                 apply: function(value) { this.date = +value; }
34921               },
34922               {
34923                 key: 'd',
34924                 regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
34925                 apply: function(value) { this.date = +value; }
34926               },
34927               {
34928                 key: 'EEEE',
34929                 regex: $locale.DATETIME_FORMATS.DAY.join('|')
34930               },
34931               {
34932                 key: 'EEE',
34933                 regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
34934               },
34935               {
34936                 key: 'HH',
34937                 regex: '(?:0|1)[0-9]|2[0-3]',
34938                 apply: function(value) { this.hours = +value; }
34939               },
34940               {
34941                 key: 'hh',
34942                 regex: '0[0-9]|1[0-2]',
34943                 apply: function(value) { this.hours = +value; }
34944               },
34945               {
34946                 key: 'H',
34947                 regex: '1?[0-9]|2[0-3]',
34948                 apply: function(value) { this.hours = +value; }
34949               },
34950               {
34951                 key: 'h',
34952                 regex: '[0-9]|1[0-2]',
34953                 apply: function(value) { this.hours = +value; }
34954               },
34955               {
34956                 key: 'mm',
34957                 regex: '[0-5][0-9]',
34958                 apply: function(value) { this.minutes = +value; }
34959               },
34960               {
34961                 key: 'm',
34962                 regex: '[0-9]|[1-5][0-9]',
34963                 apply: function(value) { this.minutes = +value; }
34964               },
34965               {
34966                 key: 'sss',
34967                 regex: '[0-9][0-9][0-9]',
34968                 apply: function(value) { this.milliseconds = +value; }
34969               },
34970               {
34971                 key: 'ss',
34972                 regex: '[0-5][0-9]',
34973                 apply: function(value) { this.seconds = +value; }
34974               },
34975               {
34976                 key: 's',
34977                 regex: '[0-9]|[1-5][0-9]',
34978                 apply: function(value) { this.seconds = +value; }
34979               },
34980               {
34981                 key: 'a',
34982                 regex: $locale.DATETIME_FORMATS.AMPMS.join('|'),
34983                 apply: function(value) {
34984                   if (this.hours === 12) {
34985                     this.hours = 0;
34986                   }
34987
34988                   if (value === 'PM') {
34989                     this.hours += 12;
34990                   }
34991                 }
34992               },
34993               {
34994                 key: 'Z',
34995                 regex: '[+-]\\d{4}',
34996                 apply: function(value) {
34997                   var matches = value.match(/([+-])(\d{2})(\d{2})/),
34998                     sign = matches[1],
34999                     hours = matches[2],
35000                     minutes = matches[3];
35001                   this.hours += toInt(sign + hours);
35002                   this.minutes += toInt(sign + minutes);
35003                 }
35004               },
35005               {
35006                 key: 'ww',
35007                 regex: '[0-4][0-9]|5[0-3]'
35008               },
35009               {
35010                 key: 'w',
35011                 regex: '[0-9]|[1-4][0-9]|5[0-3]'
35012               },
35013               {
35014                 key: 'GGGG',
35015                 regex: $locale.DATETIME_FORMATS.ERANAMES.join('|').replace(/\s/g, '\\s')
35016               },
35017               {
35018                 key: 'GGG',
35019                 regex: $locale.DATETIME_FORMATS.ERAS.join('|')
35020               },
35021               {
35022                 key: 'GG',
35023                 regex: $locale.DATETIME_FORMATS.ERAS.join('|')
35024               },
35025               {
35026                 key: 'G',
35027                 regex: $locale.DATETIME_FORMATS.ERAS.join('|')
35028               }
35029             ];
35030           };
35031
35032           this.init();
35033
35034           function createParser(format) {
35035             var map = [], regex = format.split('');
35036
35037             // check for literal values
35038             var quoteIndex = format.indexOf('\'');
35039             if (quoteIndex > -1) {
35040               var inLiteral = false;
35041               format = format.split('');
35042               for (var i = quoteIndex; i < format.length; i++) {
35043                 if (inLiteral) {
35044                   if (format[i] === '\'') {
35045                     if (i + 1 < format.length && format[i+1] === '\'') { // escaped single quote
35046                       format[i+1] = '$';
35047                       regex[i+1] = '';
35048                     } else { // end of literal
35049                       regex[i] = '';
35050                       inLiteral = false;
35051                     }
35052                   }
35053                   format[i] = '$';
35054                 } else {
35055                   if (format[i] === '\'') { // start of literal
35056                     format[i] = '$';
35057                     regex[i] = '';
35058                     inLiteral = true;
35059                   }
35060                 }
35061               }
35062
35063               format = format.join('');
35064             }
35065
35066             angular.forEach(formatCodeToRegex, function(data) {
35067               var index = format.indexOf(data.key);
35068
35069               if (index > -1) {
35070                 format = format.split('');
35071
35072                 regex[index] = '(' + data.regex + ')';
35073                 format[index] = '$'; // Custom symbol to define consumed part of format
35074                 for (var i = index + 1, n = index + data.key.length; i < n; i++) {
35075                   regex[i] = '';
35076                   format[i] = '$';
35077                 }
35078                 format = format.join('');
35079
35080                 map.push({
35081                   index: index,
35082                   apply: data.apply,
35083                   matcher: data.regex
35084                 });
35085               }
35086             });
35087
35088             return {
35089               regex: new RegExp('^' + regex.join('') + '$'),
35090               map: orderByFilter(map, 'index')
35091             };
35092           }
35093
35094           this.parse = function(input, format, baseDate) {
35095             if (!angular.isString(input) || !format) {
35096               return input;
35097             }
35098
35099             format = $locale.DATETIME_FORMATS[format] || format;
35100             format = format.replace(SPECIAL_CHARACTERS_REGEXP, '\\$&');
35101
35102             if ($locale.id !== localeId) {
35103               this.init();
35104             }
35105
35106             if (!this.parsers[format]) {
35107               this.parsers[format] = createParser(format);
35108             }
35109
35110             var parser = this.parsers[format],
35111                 regex = parser.regex,
35112                 map = parser.map,
35113                 results = input.match(regex),
35114                 tzOffset = false;
35115             if (results && results.length) {
35116               var fields, dt;
35117               if (angular.isDate(baseDate) && !isNaN(baseDate.getTime())) {
35118                 fields = {
35119                   year: baseDate.getFullYear(),
35120                   month: baseDate.getMonth(),
35121                   date: baseDate.getDate(),
35122                   hours: baseDate.getHours(),
35123                   minutes: baseDate.getMinutes(),
35124                   seconds: baseDate.getSeconds(),
35125                   milliseconds: baseDate.getMilliseconds()
35126                 };
35127               } else {
35128                 if (baseDate) {
35129                   $log.warn('dateparser:', 'baseDate is not a valid date');
35130                 }
35131                 fields = { year: 1900, month: 0, date: 1, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 };
35132               }
35133
35134               for (var i = 1, n = results.length; i < n; i++) {
35135                 var mapper = map[i - 1];
35136                 if (mapper.matcher === 'Z') {
35137                   tzOffset = true;
35138                 }
35139
35140                 if (mapper.apply) {
35141                   mapper.apply.call(fields, results[i]);
35142                 }
35143               }
35144
35145               var datesetter = tzOffset ? Date.prototype.setUTCFullYear :
35146                 Date.prototype.setFullYear;
35147               var timesetter = tzOffset ? Date.prototype.setUTCHours :
35148                 Date.prototype.setHours;
35149
35150               if (isValid(fields.year, fields.month, fields.date)) {
35151                 if (angular.isDate(baseDate) && !isNaN(baseDate.getTime()) && !tzOffset) {
35152                   dt = new Date(baseDate);
35153                   datesetter.call(dt, fields.year, fields.month, fields.date);
35154                   timesetter.call(dt, fields.hours, fields.minutes,
35155                     fields.seconds, fields.milliseconds);
35156                 } else {
35157                   dt = new Date(0);
35158                   datesetter.call(dt, fields.year, fields.month, fields.date);
35159                   timesetter.call(dt, fields.hours || 0, fields.minutes || 0,
35160                     fields.seconds || 0, fields.milliseconds || 0);
35161                 }
35162               }
35163
35164               return dt;
35165             }
35166           };
35167
35168           // Check if date is valid for specific month (and year for February).
35169           // Month: 0 = Jan, 1 = Feb, etc
35170           function isValid(year, month, date) {
35171             if (date < 1) {
35172               return false;
35173             }
35174
35175             if (month === 1 && date > 28) {
35176               return date === 29 && (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0);
35177             }
35178
35179             if (month === 3 || month === 5 || month === 8 || month === 10) {
35180               return date < 31;
35181             }
35182
35183             return true;
35184           }
35185
35186           function toInt(str) {
35187             return parseInt(str, 10);
35188           }
35189
35190           this.toTimezone = toTimezone;
35191           this.fromTimezone = fromTimezone;
35192           this.timezoneToOffset = timezoneToOffset;
35193           this.addDateMinutes = addDateMinutes;
35194           this.convertTimezoneToLocal = convertTimezoneToLocal;
35195           
35196           function toTimezone(date, timezone) {
35197             return date && timezone ? convertTimezoneToLocal(date, timezone) : date;
35198           }
35199
35200           function fromTimezone(date, timezone) {
35201             return date && timezone ? convertTimezoneToLocal(date, timezone, true) : date;
35202           }
35203
35204           //https://github.com/angular/angular.js/blob/4daafd3dbe6a80d578f5a31df1bb99c77559543e/src/Angular.js#L1207
35205           function timezoneToOffset(timezone, fallback) {
35206             var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
35207             return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
35208           }
35209
35210           function addDateMinutes(date, minutes) {
35211             date = new Date(date.getTime());
35212             date.setMinutes(date.getMinutes() + minutes);
35213             return date;
35214           }
35215
35216           function convertTimezoneToLocal(date, timezone, reverse) {
35217             reverse = reverse ? -1 : 1;
35218             var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
35219             return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
35220           }
35221         }]);
35222
35223         // Avoiding use of ng-class as it creates a lot of watchers when a class is to be applied to
35224         // at most one element.
35225         angular.module('ui.bootstrap.isClass', [])
35226         .directive('uibIsClass', [
35227                  '$animate',
35228         function ($animate) {
35229           //                    11111111          22222222
35230           var ON_REGEXP = /^\s*([\s\S]+?)\s+on\s+([\s\S]+?)\s*$/;
35231           //                    11111111           22222222
35232           var IS_REGEXP = /^\s*([\s\S]+?)\s+for\s+([\s\S]+?)\s*$/;
35233
35234           var dataPerTracked = {};
35235
35236           return {
35237             restrict: 'A',
35238             compile: function (tElement, tAttrs) {
35239               var linkedScopes = [];
35240               var instances = [];
35241               var expToData = {};
35242               var lastActivated = null;
35243               var onExpMatches = tAttrs.uibIsClass.match(ON_REGEXP);
35244               var onExp = onExpMatches[2];
35245               var expsStr = onExpMatches[1];
35246               var exps = expsStr.split(',');
35247
35248               return linkFn;
35249
35250               function linkFn(scope, element, attrs) {
35251                 linkedScopes.push(scope);
35252                 instances.push({
35253                   scope: scope,
35254                   element: element
35255                 });
35256
35257                 exps.forEach(function (exp, k) {
35258                   addForExp(exp, scope);
35259                 });
35260
35261                 scope.$on('$destroy', removeScope);
35262               }
35263
35264               function addForExp(exp, scope) {
35265                 var matches = exp.match(IS_REGEXP);
35266                 var clazz = scope.$eval(matches[1]);
35267                 var compareWithExp = matches[2];
35268                 var data = expToData[exp];
35269                 if (!data) {
35270                   var watchFn = function (compareWithVal) {
35271                     var newActivated = null;
35272                     instances.some(function (instance) {
35273                       var thisVal = instance.scope.$eval(onExp);
35274                       if (thisVal === compareWithVal) {
35275                         newActivated = instance;
35276                         return true;
35277                       }
35278                     });
35279                     if (data.lastActivated !== newActivated) {
35280                       if (data.lastActivated) {
35281                         $animate.removeClass(data.lastActivated.element, clazz);
35282                       }
35283                       if (newActivated) {
35284                         $animate.addClass(newActivated.element, clazz);
35285                       }
35286                       data.lastActivated = newActivated;
35287                     }
35288                   };
35289                   expToData[exp] = data = {
35290                     lastActivated: null,
35291                     scope: scope,
35292                     watchFn: watchFn,
35293                     compareWithExp: compareWithExp,
35294                     watcher: scope.$watch(compareWithExp, watchFn)
35295                   };
35296                 }
35297                 data.watchFn(scope.$eval(compareWithExp));
35298               }
35299
35300               function removeScope(e) {
35301                 var removedScope = e.targetScope;
35302                 var index = linkedScopes.indexOf(removedScope);
35303                 linkedScopes.splice(index, 1);
35304                 instances.splice(index, 1);
35305                 if (linkedScopes.length) {
35306                   var newWatchScope = linkedScopes[0];
35307                   angular.forEach(expToData, function (data) {
35308                     if (data.scope === removedScope) {
35309                       data.watcher = newWatchScope.$watch(data.compareWithExp, data.watchFn);
35310                       data.scope = newWatchScope;
35311                     }
35312                   });
35313                 }
35314                 else {
35315                   expToData = {};
35316                 }
35317               }
35318             }
35319           };
35320         }]);
35321         angular.module('ui.bootstrap.position', [])
35322
35323         /**
35324          * A set of utility methods for working with the DOM.
35325          * It is meant to be used where we need to absolute-position elements in
35326          * relation to another element (this is the case for tooltips, popovers,
35327          * typeahead suggestions etc.).
35328          */
35329           .factory('$uibPosition', ['$document', '$window', function($document, $window) {
35330             /**
35331              * Used by scrollbarWidth() function to cache scrollbar's width.
35332              * Do not access this variable directly, use scrollbarWidth() instead.
35333              */
35334             var SCROLLBAR_WIDTH;
35335             var OVERFLOW_REGEX = {
35336               normal: /(auto|scroll)/,
35337               hidden: /(auto|scroll|hidden)/
35338             };
35339             var PLACEMENT_REGEX = {
35340               auto: /\s?auto?\s?/i,
35341               primary: /^(top|bottom|left|right)$/,
35342               secondary: /^(top|bottom|left|right|center)$/,
35343               vertical: /^(top|bottom)$/
35344             };
35345
35346             return {
35347
35348               /**
35349                * Provides a raw DOM element from a jQuery/jQLite element.
35350                *
35351                * @param {element} elem - The element to convert.
35352                *
35353                * @returns {element} A HTML element.
35354                */
35355               getRawNode: function(elem) {
35356                 return elem[0] || elem;
35357               },
35358
35359               /**
35360                * Provides a parsed number for a style property.  Strips
35361                * units and casts invalid numbers to 0.
35362                *
35363                * @param {string} value - The style value to parse.
35364                *
35365                * @returns {number} A valid number.
35366                */
35367               parseStyle: function(value) {
35368                 value = parseFloat(value);
35369                 return isFinite(value) ? value : 0;
35370               },
35371
35372               /**
35373                * Provides the closest positioned ancestor.
35374                *
35375                * @param {element} element - The element to get the offest parent for.
35376                *
35377                * @returns {element} The closest positioned ancestor.
35378                */
35379               offsetParent: function(elem) {
35380                 elem = this.getRawNode(elem);
35381
35382                 var offsetParent = elem.offsetParent || $document[0].documentElement;
35383
35384                 function isStaticPositioned(el) {
35385                   return ($window.getComputedStyle(el).position || 'static') === 'static';
35386                 }
35387
35388                 while (offsetParent && offsetParent !== $document[0].documentElement && isStaticPositioned(offsetParent)) {
35389                   offsetParent = offsetParent.offsetParent;
35390                 }
35391
35392                 return offsetParent || $document[0].documentElement;
35393               },
35394
35395               /**
35396                * Provides the scrollbar width, concept from TWBS measureScrollbar()
35397                * function in https://github.com/twbs/bootstrap/blob/master/js/modal.js
35398                *
35399                * @returns {number} The width of the browser scollbar.
35400                */
35401               scrollbarWidth: function() {
35402                 if (angular.isUndefined(SCROLLBAR_WIDTH)) {
35403                   var scrollElem = angular.element('<div style="position: absolute; top: -9999px; width: 50px; height: 50px; overflow: scroll;"></div>');
35404                   $document.find('body').append(scrollElem);
35405                   SCROLLBAR_WIDTH = scrollElem[0].offsetWidth - scrollElem[0].clientWidth;
35406                   SCROLLBAR_WIDTH = isFinite(SCROLLBAR_WIDTH) ? SCROLLBAR_WIDTH : 0;
35407                   scrollElem.remove();
35408                 }
35409
35410                 return SCROLLBAR_WIDTH;
35411               },
35412
35413               /**
35414                * Provides the closest scrollable ancestor.
35415                * A port of the jQuery UI scrollParent method:
35416                * https://github.com/jquery/jquery-ui/blob/master/ui/scroll-parent.js
35417                *
35418                * @param {element} elem - The element to find the scroll parent of.
35419                * @param {boolean=} [includeHidden=false] - Should scroll style of 'hidden' be considered,
35420                *   default is false.
35421                *
35422                * @returns {element} A HTML element.
35423                */
35424               scrollParent: function(elem, includeHidden) {
35425                 elem = this.getRawNode(elem);
35426
35427                 var overflowRegex = includeHidden ? OVERFLOW_REGEX.hidden : OVERFLOW_REGEX.normal;
35428                 var documentEl = $document[0].documentElement;
35429                 var elemStyle = $window.getComputedStyle(elem);
35430                 var excludeStatic = elemStyle.position === 'absolute';
35431                 var scrollParent = elem.parentElement || documentEl;
35432
35433                 if (scrollParent === documentEl || elemStyle.position === 'fixed') {
35434                   return documentEl;
35435                 }
35436
35437                 while (scrollParent.parentElement && scrollParent !== documentEl) {
35438                   var spStyle = $window.getComputedStyle(scrollParent);
35439                   if (excludeStatic && spStyle.position !== 'static') {
35440                     excludeStatic = false;
35441                   }
35442
35443                   if (!excludeStatic && overflowRegex.test(spStyle.overflow + spStyle.overflowY + spStyle.overflowX)) {
35444                     break;
35445                   }
35446                   scrollParent = scrollParent.parentElement;
35447                 }
35448
35449                 return scrollParent;
35450               },
35451
35452               /**
35453                * Provides read-only equivalent of jQuery's position function:
35454                * http://api.jquery.com/position/ - distance to closest positioned
35455                * ancestor.  Does not account for margins by default like jQuery position.
35456                *
35457                * @param {element} elem - The element to caclulate the position on.
35458                * @param {boolean=} [includeMargins=false] - Should margins be accounted
35459                * for, default is false.
35460                *
35461                * @returns {object} An object with the following properties:
35462                *   <ul>
35463                *     <li>**width**: the width of the element</li>
35464                *     <li>**height**: the height of the element</li>
35465                *     <li>**top**: distance to top edge of offset parent</li>
35466                *     <li>**left**: distance to left edge of offset parent</li>
35467                *   </ul>
35468                */
35469               position: function(elem, includeMagins) {
35470                 elem = this.getRawNode(elem);
35471
35472                 var elemOffset = this.offset(elem);
35473                 if (includeMagins) {
35474                   var elemStyle = $window.getComputedStyle(elem);
35475                   elemOffset.top -= this.parseStyle(elemStyle.marginTop);
35476                   elemOffset.left -= this.parseStyle(elemStyle.marginLeft);
35477                 }
35478                 var parent = this.offsetParent(elem);
35479                 var parentOffset = {top: 0, left: 0};
35480
35481                 if (parent !== $document[0].documentElement) {
35482                   parentOffset = this.offset(parent);
35483                   parentOffset.top += parent.clientTop - parent.scrollTop;
35484                   parentOffset.left += parent.clientLeft - parent.scrollLeft;
35485                 }
35486
35487                 return {
35488                   width: Math.round(angular.isNumber(elemOffset.width) ? elemOffset.width : elem.offsetWidth),
35489                   height: Math.round(angular.isNumber(elemOffset.height) ? elemOffset.height : elem.offsetHeight),
35490                   top: Math.round(elemOffset.top - parentOffset.top),
35491                   left: Math.round(elemOffset.left - parentOffset.left)
35492                 };
35493               },
35494
35495               /**
35496                * Provides read-only equivalent of jQuery's offset function:
35497                * http://api.jquery.com/offset/ - distance to viewport.  Does
35498                * not account for borders, margins, or padding on the body
35499                * element.
35500                *
35501                * @param {element} elem - The element to calculate the offset on.
35502                *
35503                * @returns {object} An object with the following properties:
35504                *   <ul>
35505                *     <li>**width**: the width of the element</li>
35506                *     <li>**height**: the height of the element</li>
35507                *     <li>**top**: distance to top edge of viewport</li>
35508                *     <li>**right**: distance to bottom edge of viewport</li>
35509                *   </ul>
35510                */
35511               offset: function(elem) {
35512                 elem = this.getRawNode(elem);
35513
35514                 var elemBCR = elem.getBoundingClientRect();
35515                 return {
35516                   width: Math.round(angular.isNumber(elemBCR.width) ? elemBCR.width : elem.offsetWidth),
35517                   height: Math.round(angular.isNumber(elemBCR.height) ? elemBCR.height : elem.offsetHeight),
35518                   top: Math.round(elemBCR.top + ($window.pageYOffset || $document[0].documentElement.scrollTop)),
35519                   left: Math.round(elemBCR.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft))
35520                 };
35521               },
35522
35523               /**
35524                * Provides offset distance to the closest scrollable ancestor
35525                * or viewport.  Accounts for border and scrollbar width.
35526                *
35527                * Right and bottom dimensions represent the distance to the
35528                * respective edge of the viewport element.  If the element
35529                * edge extends beyond the viewport, a negative value will be
35530                * reported.
35531                *
35532                * @param {element} elem - The element to get the viewport offset for.
35533                * @param {boolean=} [useDocument=false] - Should the viewport be the document element instead
35534                * of the first scrollable element, default is false.
35535                * @param {boolean=} [includePadding=true] - Should the padding on the offset parent element
35536                * be accounted for, default is true.
35537                *
35538                * @returns {object} An object with the following properties:
35539                *   <ul>
35540                *     <li>**top**: distance to the top content edge of viewport element</li>
35541                *     <li>**bottom**: distance to the bottom content edge of viewport element</li>
35542                *     <li>**left**: distance to the left content edge of viewport element</li>
35543                *     <li>**right**: distance to the right content edge of viewport element</li>
35544                *   </ul>
35545                */
35546               viewportOffset: function(elem, useDocument, includePadding) {
35547                 elem = this.getRawNode(elem);
35548                 includePadding = includePadding !== false ? true : false;
35549
35550                 var elemBCR = elem.getBoundingClientRect();
35551                 var offsetBCR = {top: 0, left: 0, bottom: 0, right: 0};
35552
35553                 var offsetParent = useDocument ? $document[0].documentElement : this.scrollParent(elem);
35554                 var offsetParentBCR = offsetParent.getBoundingClientRect();
35555
35556                 offsetBCR.top = offsetParentBCR.top + offsetParent.clientTop;
35557                 offsetBCR.left = offsetParentBCR.left + offsetParent.clientLeft;
35558                 if (offsetParent === $document[0].documentElement) {
35559                   offsetBCR.top += $window.pageYOffset;
35560                   offsetBCR.left += $window.pageXOffset;
35561                 }
35562                 offsetBCR.bottom = offsetBCR.top + offsetParent.clientHeight;
35563                 offsetBCR.right = offsetBCR.left + offsetParent.clientWidth;
35564
35565                 if (includePadding) {
35566                   var offsetParentStyle = $window.getComputedStyle(offsetParent);
35567                   offsetBCR.top += this.parseStyle(offsetParentStyle.paddingTop);
35568                   offsetBCR.bottom -= this.parseStyle(offsetParentStyle.paddingBottom);
35569                   offsetBCR.left += this.parseStyle(offsetParentStyle.paddingLeft);
35570                   offsetBCR.right -= this.parseStyle(offsetParentStyle.paddingRight);
35571                 }
35572
35573                 return {
35574                   top: Math.round(elemBCR.top - offsetBCR.top),
35575                   bottom: Math.round(offsetBCR.bottom - elemBCR.bottom),
35576                   left: Math.round(elemBCR.left - offsetBCR.left),
35577                   right: Math.round(offsetBCR.right - elemBCR.right)
35578                 };
35579               },
35580
35581               /**
35582                * Provides an array of placement values parsed from a placement string.
35583                * Along with the 'auto' indicator, supported placement strings are:
35584                *   <ul>
35585                *     <li>top: element on top, horizontally centered on host element.</li>
35586                *     <li>top-left: element on top, left edge aligned with host element left edge.</li>
35587                *     <li>top-right: element on top, lerightft edge aligned with host element right edge.</li>
35588                *     <li>bottom: element on bottom, horizontally centered on host element.</li>
35589                *     <li>bottom-left: element on bottom, left edge aligned with host element left edge.</li>
35590                *     <li>bottom-right: element on bottom, right edge aligned with host element right edge.</li>
35591                *     <li>left: element on left, vertically centered on host element.</li>
35592                *     <li>left-top: element on left, top edge aligned with host element top edge.</li>
35593                *     <li>left-bottom: element on left, bottom edge aligned with host element bottom edge.</li>
35594                *     <li>right: element on right, vertically centered on host element.</li>
35595                *     <li>right-top: element on right, top edge aligned with host element top edge.</li>
35596                *     <li>right-bottom: element on right, bottom edge aligned with host element bottom edge.</li>
35597                *   </ul>
35598                * A placement string with an 'auto' indicator is expected to be
35599                * space separated from the placement, i.e: 'auto bottom-left'  If
35600                * the primary and secondary placement values do not match 'top,
35601                * bottom, left, right' then 'top' will be the primary placement and
35602                * 'center' will be the secondary placement.  If 'auto' is passed, true
35603                * will be returned as the 3rd value of the array.
35604                *
35605                * @param {string} placement - The placement string to parse.
35606                *
35607                * @returns {array} An array with the following values
35608                * <ul>
35609                *   <li>**[0]**: The primary placement.</li>
35610                *   <li>**[1]**: The secondary placement.</li>
35611                *   <li>**[2]**: If auto is passed: true, else undefined.</li>
35612                * </ul>
35613                */
35614               parsePlacement: function(placement) {
35615                 var autoPlace = PLACEMENT_REGEX.auto.test(placement);
35616                 if (autoPlace) {
35617                   placement = placement.replace(PLACEMENT_REGEX.auto, '');
35618                 }
35619
35620                 placement = placement.split('-');
35621
35622                 placement[0] = placement[0] || 'top';
35623                 if (!PLACEMENT_REGEX.primary.test(placement[0])) {
35624                   placement[0] = 'top';
35625                 }
35626
35627                 placement[1] = placement[1] || 'center';
35628                 if (!PLACEMENT_REGEX.secondary.test(placement[1])) {
35629                   placement[1] = 'center';
35630                 }
35631
35632                 if (autoPlace) {
35633                   placement[2] = true;
35634                 } else {
35635                   placement[2] = false;
35636                 }
35637
35638                 return placement;
35639               },
35640
35641               /**
35642                * Provides coordinates for an element to be positioned relative to
35643                * another element.  Passing 'auto' as part of the placement parameter
35644                * will enable smart placement - where the element fits. i.e:
35645                * 'auto left-top' will check to see if there is enough space to the left
35646                * of the hostElem to fit the targetElem, if not place right (same for secondary
35647                * top placement).  Available space is calculated using the viewportOffset
35648                * function.
35649                *
35650                * @param {element} hostElem - The element to position against.
35651                * @param {element} targetElem - The element to position.
35652                * @param {string=} [placement=top] - The placement for the targetElem,
35653                *   default is 'top'. 'center' is assumed as secondary placement for
35654                *   'top', 'left', 'right', and 'bottom' placements.  Available placements are:
35655                *   <ul>
35656                *     <li>top</li>
35657                *     <li>top-right</li>
35658                *     <li>top-left</li>
35659                *     <li>bottom</li>
35660                *     <li>bottom-left</li>
35661                *     <li>bottom-right</li>
35662                *     <li>left</li>
35663                *     <li>left-top</li>
35664                *     <li>left-bottom</li>
35665                *     <li>right</li>
35666                *     <li>right-top</li>
35667                *     <li>right-bottom</li>
35668                *   </ul>
35669                * @param {boolean=} [appendToBody=false] - Should the top and left values returned
35670                *   be calculated from the body element, default is false.
35671                *
35672                * @returns {object} An object with the following properties:
35673                *   <ul>
35674                *     <li>**top**: Value for targetElem top.</li>
35675                *     <li>**left**: Value for targetElem left.</li>
35676                *     <li>**placement**: The resolved placement.</li>
35677                *   </ul>
35678                */
35679               positionElements: function(hostElem, targetElem, placement, appendToBody) {
35680                 hostElem = this.getRawNode(hostElem);
35681                 targetElem = this.getRawNode(targetElem);
35682
35683                 // need to read from prop to support tests.
35684                 var targetWidth = angular.isDefined(targetElem.offsetWidth) ? targetElem.offsetWidth : targetElem.prop('offsetWidth');
35685                 var targetHeight = angular.isDefined(targetElem.offsetHeight) ? targetElem.offsetHeight : targetElem.prop('offsetHeight');
35686
35687                 placement = this.parsePlacement(placement);
35688
35689                 var hostElemPos = appendToBody ? this.offset(hostElem) : this.position(hostElem);
35690                 var targetElemPos = {top: 0, left: 0, placement: ''};
35691
35692                 if (placement[2]) {
35693                   var viewportOffset = this.viewportOffset(hostElem);
35694
35695                   var targetElemStyle = $window.getComputedStyle(targetElem);
35696                   var adjustedSize = {
35697                     width: targetWidth + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginLeft) + this.parseStyle(targetElemStyle.marginRight))),
35698                     height: targetHeight + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginTop) + this.parseStyle(targetElemStyle.marginBottom)))
35699                   };
35700
35701                   placement[0] = placement[0] === 'top' && adjustedSize.height > viewportOffset.top && adjustedSize.height <= viewportOffset.bottom ? 'bottom' :
35702                                  placement[0] === 'bottom' && adjustedSize.height > viewportOffset.bottom && adjustedSize.height <= viewportOffset.top ? 'top' :
35703                                  placement[0] === 'left' && adjustedSize.width > viewportOffset.left && adjustedSize.width <= viewportOffset.right ? 'right' :
35704                                  placement[0] === 'right' && adjustedSize.width > viewportOffset.right && adjustedSize.width <= viewportOffset.left ? 'left' :
35705                                  placement[0];
35706
35707                   placement[1] = placement[1] === 'top' && adjustedSize.height - hostElemPos.height > viewportOffset.bottom && adjustedSize.height - hostElemPos.height <= viewportOffset.top ? 'bottom' :
35708                                  placement[1] === 'bottom' && adjustedSize.height - hostElemPos.height > viewportOffset.top && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom ? 'top' :
35709                                  placement[1] === 'left' && adjustedSize.width - hostElemPos.width > viewportOffset.right && adjustedSize.width - hostElemPos.width <= viewportOffset.left ? 'right' :
35710                                  placement[1] === 'right' && adjustedSize.width - hostElemPos.width > viewportOffset.left && adjustedSize.width - hostElemPos.width <= viewportOffset.right ? 'left' :
35711                                  placement[1];
35712
35713                   if (placement[1] === 'center') {
35714                     if (PLACEMENT_REGEX.vertical.test(placement[0])) {
35715                       var xOverflow = hostElemPos.width / 2 - targetWidth / 2;
35716                       if (viewportOffset.left + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.right) {
35717                         placement[1] = 'left';
35718                       } else if (viewportOffset.right + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.left) {
35719                         placement[1] = 'right';
35720                       }
35721                     } else {
35722                       var yOverflow = hostElemPos.height / 2 - adjustedSize.height / 2;
35723                       if (viewportOffset.top + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom) {
35724                         placement[1] = 'top';
35725                       } else if (viewportOffset.bottom + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.top) {
35726                         placement[1] = 'bottom';
35727                       }
35728                     }
35729                   }
35730                 }
35731
35732                 switch (placement[0]) {
35733                   case 'top':
35734                     targetElemPos.top = hostElemPos.top - targetHeight;
35735                     break;
35736                   case 'bottom':
35737                     targetElemPos.top = hostElemPos.top + hostElemPos.height;
35738                     break;
35739                   case 'left':
35740                     targetElemPos.left = hostElemPos.left - targetWidth;
35741                     break;
35742                   case 'right':
35743                     targetElemPos.left = hostElemPos.left + hostElemPos.width;
35744                     break;
35745                 }
35746
35747                 switch (placement[1]) {
35748                   case 'top':
35749                     targetElemPos.top = hostElemPos.top;
35750                     break;
35751                   case 'bottom':
35752                     targetElemPos.top = hostElemPos.top + hostElemPos.height - targetHeight;
35753                     break;
35754                   case 'left':
35755                     targetElemPos.left = hostElemPos.left;
35756                     break;
35757                   case 'right':
35758                     targetElemPos.left = hostElemPos.left + hostElemPos.width - targetWidth;
35759                     break;
35760                   case 'center':
35761                     if (PLACEMENT_REGEX.vertical.test(placement[0])) {
35762                       targetElemPos.left = hostElemPos.left + hostElemPos.width / 2 - targetWidth / 2;
35763                     } else {
35764                       targetElemPos.top = hostElemPos.top + hostElemPos.height / 2 - targetHeight / 2;
35765                     }
35766                     break;
35767                 }
35768
35769                 targetElemPos.top = Math.round(targetElemPos.top);
35770                 targetElemPos.left = Math.round(targetElemPos.left);
35771                 targetElemPos.placement = placement[1] === 'center' ? placement[0] : placement[0] + '-' + placement[1];
35772
35773                 return targetElemPos;
35774               },
35775
35776               /**
35777               * Provides a way for positioning tooltip & dropdown
35778               * arrows when using placement options beyond the standard
35779               * left, right, top, or bottom.
35780               *
35781               * @param {element} elem - The tooltip/dropdown element.
35782               * @param {string} placement - The placement for the elem.
35783               */
35784               positionArrow: function(elem, placement) {
35785                 elem = this.getRawNode(elem);
35786
35787                 var isTooltip = true;
35788
35789                 var innerElem = elem.querySelector('.tooltip-inner');
35790                 if (!innerElem) {
35791                   isTooltip = false;
35792                   innerElem = elem.querySelector('.popover-inner');
35793                 }
35794                 if (!innerElem) {
35795                   return;
35796                 }
35797
35798                 var arrowElem = isTooltip ? elem.querySelector('.tooltip-arrow') : elem.querySelector('.arrow');
35799                 if (!arrowElem) {
35800                   return;
35801                 }
35802
35803                 placement = this.parsePlacement(placement);
35804                 if (placement[1] === 'center') {
35805                   // no adjustment necessary - just reset styles
35806                   angular.element(arrowElem).css({top: '', bottom: '', right: '', left: '', margin: ''});
35807                   return;
35808                 }
35809
35810                 var borderProp = 'border-' + placement[0] + '-width';
35811                 var borderWidth = $window.getComputedStyle(arrowElem)[borderProp];
35812
35813                 var borderRadiusProp = 'border-';
35814                 if (PLACEMENT_REGEX.vertical.test(placement[0])) {
35815                   borderRadiusProp += placement[0] + '-' + placement[1];
35816                 } else {
35817                   borderRadiusProp += placement[1] + '-' + placement[0];
35818                 }
35819                 borderRadiusProp += '-radius';
35820                 var borderRadius = $window.getComputedStyle(isTooltip ? innerElem : elem)[borderRadiusProp];
35821
35822                 var arrowCss = {
35823                   top: 'auto',
35824                   bottom: 'auto',
35825                   left: 'auto',
35826                   right: 'auto',
35827                   margin: 0
35828                 };
35829
35830                 switch (placement[0]) {
35831                   case 'top':
35832                     arrowCss.bottom = isTooltip ? '0' : '-' + borderWidth;
35833                     break;
35834                   case 'bottom':
35835                     arrowCss.top = isTooltip ? '0' : '-' + borderWidth;
35836                     break;
35837                   case 'left':
35838                     arrowCss.right = isTooltip ? '0' : '-' + borderWidth;
35839                     break;
35840                   case 'right':
35841                     arrowCss.left = isTooltip ? '0' : '-' + borderWidth;
35842                     break;
35843                 }
35844
35845                 arrowCss[placement[1]] = borderRadius;
35846
35847                 angular.element(arrowElem).css(arrowCss);
35848               }
35849             };
35850           }]);
35851
35852         angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.isClass', 'ui.bootstrap.position'])
35853
35854         .value('$datepickerSuppressError', false)
35855
35856         .constant('uibDatepickerConfig', {
35857           formatDay: 'dd',
35858           formatMonth: 'MMMM',
35859           formatYear: 'yyyy',
35860           formatDayHeader: 'EEE',
35861           formatDayTitle: 'MMMM yyyy',
35862           formatMonthTitle: 'yyyy',
35863           datepickerMode: 'day',
35864           minMode: 'day',
35865           maxMode: 'year',
35866           showWeeks: true,
35867           startingDay: 0,
35868           yearRows: 4,
35869           yearColumns: 5,
35870           minDate: null,
35871           maxDate: null,
35872           shortcutPropagation: false,
35873           ngModelOptions: {}
35874         })
35875
35876         .controller('UibDatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$log', 'dateFilter', 'uibDatepickerConfig', '$datepickerSuppressError', 'uibDateParser',
35877           function($scope, $attrs, $parse, $interpolate, $log, dateFilter, datepickerConfig, $datepickerSuppressError, dateParser) {
35878           var self = this,
35879               ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl;
35880               ngModelOptions = {};
35881
35882           // Modes chain
35883           this.modes = ['day', 'month', 'year'];
35884
35885           // Interpolated configuration attributes
35886           angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle'], function(key) {
35887             self[key] = angular.isDefined($attrs[key]) ? $interpolate($attrs[key])($scope.$parent) : datepickerConfig[key];
35888           });
35889
35890           // Evaled configuration attributes
35891           angular.forEach(['showWeeks', 'startingDay', 'yearRows', 'yearColumns', 'shortcutPropagation'], function(key) {
35892             self[key] = angular.isDefined($attrs[key]) ? $scope.$parent.$eval($attrs[key]) : datepickerConfig[key];
35893           });
35894
35895           // Watchable date attributes
35896           angular.forEach(['minDate', 'maxDate'], function(key) {
35897             if ($attrs[key]) {
35898               $scope.$parent.$watch($attrs[key], function(value) {
35899                 self[key] = value ? angular.isDate(value) ? dateParser.fromTimezone(new Date(value), ngModelOptions.timezone) : new Date(dateFilter(value, 'medium')) : null;
35900                 self.refreshView();
35901               });
35902             } else {
35903               self[key] = datepickerConfig[key] ? dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.timezone) : null;
35904             }
35905           });
35906
35907           angular.forEach(['minMode', 'maxMode'], function(key) {
35908             if ($attrs[key]) {
35909               $scope.$parent.$watch($attrs[key], function(value) {
35910                 self[key] = $scope[key] = angular.isDefined(value) ? value : $attrs[key];
35911                 if (key === 'minMode' && self.modes.indexOf($scope.datepickerMode) < self.modes.indexOf(self[key]) ||
35912                   key === 'maxMode' && self.modes.indexOf($scope.datepickerMode) > self.modes.indexOf(self[key])) {
35913                   $scope.datepickerMode = self[key];
35914                 }
35915               });
35916             } else {
35917               self[key] = $scope[key] = datepickerConfig[key] || null;
35918             }
35919           });
35920
35921           $scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode;
35922           $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
35923
35924           if (angular.isDefined($attrs.initDate)) {
35925             this.activeDate = dateParser.fromTimezone($scope.$parent.$eval($attrs.initDate), ngModelOptions.timezone) || new Date();
35926             $scope.$parent.$watch($attrs.initDate, function(initDate) {
35927               if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) {
35928                 self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.timezone);
35929                 self.refreshView();
35930               }
35931             });
35932           } else {
35933             this.activeDate = new Date();
35934           }
35935
35936           $scope.disabled = angular.isDefined($attrs.disabled) || false;
35937           if (angular.isDefined($attrs.ngDisabled)) {
35938             $scope.$parent.$watch($attrs.ngDisabled, function(disabled) {
35939               $scope.disabled = disabled;
35940               self.refreshView();
35941             });
35942           }
35943
35944           $scope.isActive = function(dateObject) {
35945             if (self.compare(dateObject.date, self.activeDate) === 0) {
35946               $scope.activeDateId = dateObject.uid;
35947               return true;
35948             }
35949             return false;
35950           };
35951
35952           this.init = function(ngModelCtrl_) {
35953             ngModelCtrl = ngModelCtrl_;
35954             ngModelOptions = ngModelCtrl_.$options || datepickerConfig.ngModelOptions;
35955
35956             if (ngModelCtrl.$modelValue) {
35957               this.activeDate = ngModelCtrl.$modelValue;
35958             }
35959
35960             ngModelCtrl.$render = function() {
35961               self.render();
35962             };
35963           };
35964
35965           this.render = function() {
35966             if (ngModelCtrl.$viewValue) {
35967               var date = new Date(ngModelCtrl.$viewValue),
35968                   isValid = !isNaN(date);
35969
35970               if (isValid) {
35971                 this.activeDate = dateParser.fromTimezone(date, ngModelOptions.timezone);
35972               } else if (!$datepickerSuppressError) {
35973                 $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
35974               }
35975             }
35976             this.refreshView();
35977           };
35978
35979           this.refreshView = function() {
35980             if (this.element) {
35981               $scope.selectedDt = null;
35982               this._refreshView();
35983               if ($scope.activeDt) {
35984                 $scope.activeDateId = $scope.activeDt.uid;
35985               }
35986
35987               var date = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
35988               date = dateParser.fromTimezone(date, ngModelOptions.timezone);
35989               ngModelCtrl.$setValidity('dateDisabled', !date ||
35990                 this.element && !this.isDisabled(date));
35991             }
35992           };
35993
35994           this.createDateObject = function(date, format) {
35995             var model = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
35996             model = dateParser.fromTimezone(model, ngModelOptions.timezone);
35997             var dt = {
35998               date: date,
35999               label: dateFilter(date, format),
36000               selected: model && this.compare(date, model) === 0,
36001               disabled: this.isDisabled(date),
36002               current: this.compare(date, new Date()) === 0,
36003               customClass: this.customClass(date) || null
36004             };
36005
36006             if (model && this.compare(date, model) === 0) {
36007               $scope.selectedDt = dt;
36008             }
36009
36010             if (self.activeDate && this.compare(dt.date, self.activeDate) === 0) {
36011               $scope.activeDt = dt;
36012             }
36013
36014             return dt;
36015           };
36016
36017           this.isDisabled = function(date) {
36018             return $scope.disabled ||
36019               this.minDate && this.compare(date, this.minDate) < 0 ||
36020               this.maxDate && this.compare(date, this.maxDate) > 0 ||
36021               $attrs.dateDisabled && $scope.dateDisabled({date: date, mode: $scope.datepickerMode});
36022           };
36023
36024           this.customClass = function(date) {
36025             return $scope.customClass({date: date, mode: $scope.datepickerMode});
36026           };
36027
36028           // Split array into smaller arrays
36029           this.split = function(arr, size) {
36030             var arrays = [];
36031             while (arr.length > 0) {
36032               arrays.push(arr.splice(0, size));
36033             }
36034             return arrays;
36035           };
36036
36037           $scope.select = function(date) {
36038             if ($scope.datepickerMode === self.minMode) {
36039               var dt = ngModelCtrl.$viewValue ? dateParser.fromTimezone(new Date(ngModelCtrl.$viewValue), ngModelOptions.timezone) : new Date(0, 0, 0, 0, 0, 0, 0);
36040               dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
36041               dt = dateParser.toTimezone(dt, ngModelOptions.timezone);
36042               ngModelCtrl.$setViewValue(dt);
36043               ngModelCtrl.$render();
36044             } else {
36045               self.activeDate = date;
36046               $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1];
36047             }
36048           };
36049
36050           $scope.move = function(direction) {
36051             var year = self.activeDate.getFullYear() + direction * (self.step.years || 0),
36052                 month = self.activeDate.getMonth() + direction * (self.step.months || 0);
36053             self.activeDate.setFullYear(year, month, 1);
36054             self.refreshView();
36055           };
36056
36057           $scope.toggleMode = function(direction) {
36058             direction = direction || 1;
36059
36060             if ($scope.datepickerMode === self.maxMode && direction === 1 ||
36061               $scope.datepickerMode === self.minMode && direction === -1) {
36062               return;
36063             }
36064
36065             $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction];
36066           };
36067
36068           // Key event mapper
36069           $scope.keys = { 13: 'enter', 32: 'space', 33: 'pageup', 34: 'pagedown', 35: 'end', 36: 'home', 37: 'left', 38: 'up', 39: 'right', 40: 'down' };
36070
36071           var focusElement = function() {
36072             self.element[0].focus();
36073           };
36074
36075           // Listen for focus requests from popup directive
36076           $scope.$on('uib:datepicker.focus', focusElement);
36077
36078           $scope.keydown = function(evt) {
36079             var key = $scope.keys[evt.which];
36080
36081             if (!key || evt.shiftKey || evt.altKey || $scope.disabled) {
36082               return;
36083             }
36084
36085             evt.preventDefault();
36086             if (!self.shortcutPropagation) {
36087               evt.stopPropagation();
36088             }
36089
36090             if (key === 'enter' || key === 'space') {
36091               if (self.isDisabled(self.activeDate)) {
36092                 return; // do nothing
36093               }
36094               $scope.select(self.activeDate);
36095             } else if (evt.ctrlKey && (key === 'up' || key === 'down')) {
36096               $scope.toggleMode(key === 'up' ? 1 : -1);
36097             } else {
36098               self.handleKeyDown(key, evt);
36099               self.refreshView();
36100             }
36101           };
36102         }])
36103
36104         .controller('UibDaypickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36105           var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
36106
36107           this.step = { months: 1 };
36108           this.element = $element;
36109           function getDaysInMonth(year, month) {
36110             return month === 1 && year % 4 === 0 &&
36111               (year % 100 !== 0 || year % 400 === 0) ? 29 : DAYS_IN_MONTH[month];
36112           }
36113
36114           this.init = function(ctrl) {
36115             angular.extend(ctrl, this);
36116             scope.showWeeks = ctrl.showWeeks;
36117             ctrl.refreshView();
36118           };
36119
36120           this.getDates = function(startDate, n) {
36121             var dates = new Array(n), current = new Date(startDate), i = 0, date;
36122             while (i < n) {
36123               date = new Date(current);
36124               dates[i++] = date;
36125               current.setDate(current.getDate() + 1);
36126             }
36127             return dates;
36128           };
36129
36130           this._refreshView = function() {
36131             var year = this.activeDate.getFullYear(),
36132               month = this.activeDate.getMonth(),
36133               firstDayOfMonth = new Date(this.activeDate);
36134
36135             firstDayOfMonth.setFullYear(year, month, 1);
36136
36137             var difference = this.startingDay - firstDayOfMonth.getDay(),
36138               numDisplayedFromPreviousMonth = difference > 0 ?
36139                 7 - difference : - difference,
36140               firstDate = new Date(firstDayOfMonth);
36141
36142             if (numDisplayedFromPreviousMonth > 0) {
36143               firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
36144             }
36145
36146             // 42 is the number of days on a six-week calendar
36147             var days = this.getDates(firstDate, 42);
36148             for (var i = 0; i < 42; i ++) {
36149               days[i] = angular.extend(this.createDateObject(days[i], this.formatDay), {
36150                 secondary: days[i].getMonth() !== month,
36151                 uid: scope.uniqueId + '-' + i
36152               });
36153             }
36154
36155             scope.labels = new Array(7);
36156             for (var j = 0; j < 7; j++) {
36157               scope.labels[j] = {
36158                 abbr: dateFilter(days[j].date, this.formatDayHeader),
36159                 full: dateFilter(days[j].date, 'EEEE')
36160               };
36161             }
36162
36163             scope.title = dateFilter(this.activeDate, this.formatDayTitle);
36164             scope.rows = this.split(days, 7);
36165
36166             if (scope.showWeeks) {
36167               scope.weekNumbers = [];
36168               var thursdayIndex = (4 + 7 - this.startingDay) % 7,
36169                   numWeeks = scope.rows.length;
36170               for (var curWeek = 0; curWeek < numWeeks; curWeek++) {
36171                 scope.weekNumbers.push(
36172                   getISO8601WeekNumber(scope.rows[curWeek][thursdayIndex].date));
36173               }
36174             }
36175           };
36176
36177           this.compare = function(date1, date2) {
36178             var _date1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
36179             var _date2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
36180             _date1.setFullYear(date1.getFullYear());
36181             _date2.setFullYear(date2.getFullYear());
36182             return _date1 - _date2;
36183           };
36184
36185           function getISO8601WeekNumber(date) {
36186             var checkDate = new Date(date);
36187             checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
36188             var time = checkDate.getTime();
36189             checkDate.setMonth(0); // Compare with Jan 1
36190             checkDate.setDate(1);
36191             return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
36192           }
36193
36194           this.handleKeyDown = function(key, evt) {
36195             var date = this.activeDate.getDate();
36196
36197             if (key === 'left') {
36198               date = date - 1;
36199             } else if (key === 'up') {
36200               date = date - 7;
36201             } else if (key === 'right') {
36202               date = date + 1;
36203             } else if (key === 'down') {
36204               date = date + 7;
36205             } else if (key === 'pageup' || key === 'pagedown') {
36206               var month = this.activeDate.getMonth() + (key === 'pageup' ? - 1 : 1);
36207               this.activeDate.setMonth(month, 1);
36208               date = Math.min(getDaysInMonth(this.activeDate.getFullYear(), this.activeDate.getMonth()), date);
36209             } else if (key === 'home') {
36210               date = 1;
36211             } else if (key === 'end') {
36212               date = getDaysInMonth(this.activeDate.getFullYear(), this.activeDate.getMonth());
36213             }
36214             this.activeDate.setDate(date);
36215           };
36216         }])
36217
36218         .controller('UibMonthpickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36219           this.step = { years: 1 };
36220           this.element = $element;
36221
36222           this.init = function(ctrl) {
36223             angular.extend(ctrl, this);
36224             ctrl.refreshView();
36225           };
36226
36227           this._refreshView = function() {
36228             var months = new Array(12),
36229                 year = this.activeDate.getFullYear(),
36230                 date;
36231
36232             for (var i = 0; i < 12; i++) {
36233               date = new Date(this.activeDate);
36234               date.setFullYear(year, i, 1);
36235               months[i] = angular.extend(this.createDateObject(date, this.formatMonth), {
36236                 uid: scope.uniqueId + '-' + i
36237               });
36238             }
36239
36240             scope.title = dateFilter(this.activeDate, this.formatMonthTitle);
36241             scope.rows = this.split(months, 3);
36242           };
36243
36244           this.compare = function(date1, date2) {
36245             var _date1 = new Date(date1.getFullYear(), date1.getMonth());
36246             var _date2 = new Date(date2.getFullYear(), date2.getMonth());
36247             _date1.setFullYear(date1.getFullYear());
36248             _date2.setFullYear(date2.getFullYear());
36249             return _date1 - _date2;
36250           };
36251
36252           this.handleKeyDown = function(key, evt) {
36253             var date = this.activeDate.getMonth();
36254
36255             if (key === 'left') {
36256               date = date - 1;
36257             } else if (key === 'up') {
36258               date = date - 3;
36259             } else if (key === 'right') {
36260               date = date + 1;
36261             } else if (key === 'down') {
36262               date = date + 3;
36263             } else if (key === 'pageup' || key === 'pagedown') {
36264               var year = this.activeDate.getFullYear() + (key === 'pageup' ? - 1 : 1);
36265               this.activeDate.setFullYear(year);
36266             } else if (key === 'home') {
36267               date = 0;
36268             } else if (key === 'end') {
36269               date = 11;
36270             }
36271             this.activeDate.setMonth(date);
36272           };
36273         }])
36274
36275         .controller('UibYearpickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36276           var columns, range;
36277           this.element = $element;
36278
36279           function getStartingYear(year) {
36280             return parseInt((year - 1) / range, 10) * range + 1;
36281           }
36282
36283           this.yearpickerInit = function() {
36284             columns = this.yearColumns;
36285             range = this.yearRows * columns;
36286             this.step = { years: range };
36287           };
36288
36289           this._refreshView = function() {
36290             var years = new Array(range), date;
36291
36292             for (var i = 0, start = getStartingYear(this.activeDate.getFullYear()); i < range; i++) {
36293               date = new Date(this.activeDate);
36294               date.setFullYear(start + i, 0, 1);
36295               years[i] = angular.extend(this.createDateObject(date, this.formatYear), {
36296                 uid: scope.uniqueId + '-' + i
36297               });
36298             }
36299
36300             scope.title = [years[0].label, years[range - 1].label].join(' - ');
36301             scope.rows = this.split(years, columns);
36302             scope.columns = columns;
36303           };
36304
36305           this.compare = function(date1, date2) {
36306             return date1.getFullYear() - date2.getFullYear();
36307           };
36308
36309           this.handleKeyDown = function(key, evt) {
36310             var date = this.activeDate.getFullYear();
36311
36312             if (key === 'left') {
36313               date = date - 1;
36314             } else if (key === 'up') {
36315               date = date - columns;
36316             } else if (key === 'right') {
36317               date = date + 1;
36318             } else if (key === 'down') {
36319               date = date + columns;
36320             } else if (key === 'pageup' || key === 'pagedown') {
36321               date += (key === 'pageup' ? - 1 : 1) * range;
36322             } else if (key === 'home') {
36323               date = getStartingYear(this.activeDate.getFullYear());
36324             } else if (key === 'end') {
36325               date = getStartingYear(this.activeDate.getFullYear()) + range - 1;
36326             }
36327             this.activeDate.setFullYear(date);
36328           };
36329         }])
36330
36331         .directive('uibDatepicker', function() {
36332           return {
36333             replace: true,
36334             templateUrl: function(element, attrs) {
36335               return attrs.templateUrl || 'uib/template/datepicker/datepicker.html';
36336             },
36337             scope: {
36338               datepickerMode: '=?',
36339               dateDisabled: '&',
36340               customClass: '&',
36341               shortcutPropagation: '&?'
36342             },
36343             require: ['uibDatepicker', '^ngModel'],
36344             controller: 'UibDatepickerController',
36345             controllerAs: 'datepicker',
36346             link: function(scope, element, attrs, ctrls) {
36347               var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
36348
36349               datepickerCtrl.init(ngModelCtrl);
36350             }
36351           };
36352         })
36353
36354         .directive('uibDaypicker', function() {
36355           return {
36356             replace: true,
36357             templateUrl: function(element, attrs) {
36358               return attrs.templateUrl || 'uib/template/datepicker/day.html';
36359             },
36360             require: ['^uibDatepicker', 'uibDaypicker'],
36361             controller: 'UibDaypickerController',
36362             link: function(scope, element, attrs, ctrls) {
36363               var datepickerCtrl = ctrls[0],
36364                 daypickerCtrl = ctrls[1];
36365
36366               daypickerCtrl.init(datepickerCtrl);
36367             }
36368           };
36369         })
36370
36371         .directive('uibMonthpicker', function() {
36372           return {
36373             replace: true,
36374             templateUrl: function(element, attrs) {
36375               return attrs.templateUrl || 'uib/template/datepicker/month.html';
36376             },
36377             require: ['^uibDatepicker', 'uibMonthpicker'],
36378             controller: 'UibMonthpickerController',
36379             link: function(scope, element, attrs, ctrls) {
36380               var datepickerCtrl = ctrls[0],
36381                 monthpickerCtrl = ctrls[1];
36382
36383               monthpickerCtrl.init(datepickerCtrl);
36384             }
36385           };
36386         })
36387
36388         .directive('uibYearpicker', function() {
36389           return {
36390             replace: true,
36391             templateUrl: function(element, attrs) {
36392               return attrs.templateUrl || 'uib/template/datepicker/year.html';
36393             },
36394             require: ['^uibDatepicker', 'uibYearpicker'],
36395             controller: 'UibYearpickerController',
36396             link: function(scope, element, attrs, ctrls) {
36397               var ctrl = ctrls[0];
36398               angular.extend(ctrl, ctrls[1]);
36399               ctrl.yearpickerInit();
36400
36401               ctrl.refreshView();
36402             }
36403           };
36404         })
36405
36406         .constant('uibDatepickerPopupConfig', {
36407           datepickerPopup: 'yyyy-MM-dd',
36408           datepickerPopupTemplateUrl: 'uib/template/datepicker/popup.html',
36409           datepickerTemplateUrl: 'uib/template/datepicker/datepicker.html',
36410           html5Types: {
36411             date: 'yyyy-MM-dd',
36412             'datetime-local': 'yyyy-MM-ddTHH:mm:ss.sss',
36413             'month': 'yyyy-MM'
36414           },
36415           currentText: 'Today',
36416           clearText: 'Clear',
36417           closeText: 'Done',
36418           closeOnDateSelection: true,
36419           appendToBody: false,
36420           showButtonBar: true,
36421           onOpenFocus: true,
36422           altInputFormats: []
36423         })
36424
36425         .controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig',
36426         function(scope, element, attrs, $compile, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig) {
36427           var self = this;
36428           var cache = {},
36429             isHtml5DateInput = false;
36430           var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
36431             datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl,
36432             ngModel, ngModelOptions, $popup, altInputFormats;
36433
36434           scope.watchData = {};
36435
36436           this.init = function(_ngModel_) {
36437             ngModel = _ngModel_;
36438             ngModelOptions = _ngModel_.$options || datepickerConfig.ngModelOptions;
36439             closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection;
36440             appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody;
36441             onOpenFocus = angular.isDefined(attrs.onOpenFocus) ? scope.$parent.$eval(attrs.onOpenFocus) : datepickerPopupConfig.onOpenFocus;
36442             datepickerPopupTemplateUrl = angular.isDefined(attrs.datepickerPopupTemplateUrl) ? attrs.datepickerPopupTemplateUrl : datepickerPopupConfig.datepickerPopupTemplateUrl;
36443             datepickerTemplateUrl = angular.isDefined(attrs.datepickerTemplateUrl) ? attrs.datepickerTemplateUrl : datepickerPopupConfig.datepickerTemplateUrl;
36444             altInputFormats = angular.isDefined(attrs.altInputFormats) ? scope.$parent.$eval(attrs.altInputFormats) : datepickerPopupConfig.altInputFormats;
36445
36446             scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar;
36447
36448             if (datepickerPopupConfig.html5Types[attrs.type]) {
36449               dateFormat = datepickerPopupConfig.html5Types[attrs.type];
36450               isHtml5DateInput = true;
36451             } else {
36452               dateFormat = attrs.uibDatepickerPopup || datepickerPopupConfig.datepickerPopup;
36453               attrs.$observe('uibDatepickerPopup', function(value, oldValue) {
36454                   var newDateFormat = value || datepickerPopupConfig.datepickerPopup;
36455                   // Invalidate the $modelValue to ensure that formatters re-run
36456                   // FIXME: Refactor when PR is merged: https://github.com/angular/angular.js/pull/10764
36457                   if (newDateFormat !== dateFormat) {
36458                     dateFormat = newDateFormat;
36459                     ngModel.$modelValue = null;
36460
36461                     if (!dateFormat) {
36462                       throw new Error('uibDatepickerPopup must have a date format specified.');
36463                     }
36464                   }
36465               });
36466             }
36467
36468             if (!dateFormat) {
36469               throw new Error('uibDatepickerPopup must have a date format specified.');
36470             }
36471
36472             if (isHtml5DateInput && attrs.uibDatepickerPopup) {
36473               throw new Error('HTML5 date input types do not support custom formats.');
36474             }
36475
36476             // popup element used to display calendar
36477             popupEl = angular.element('<div uib-datepicker-popup-wrap><div uib-datepicker></div></div>');
36478             scope.ngModelOptions = angular.copy(ngModelOptions);
36479             scope.ngModelOptions.timezone = null;
36480             popupEl.attr({
36481               'ng-model': 'date',
36482               'ng-model-options': 'ngModelOptions',
36483               'ng-change': 'dateSelection(date)',
36484               'template-url': datepickerPopupTemplateUrl
36485             });
36486
36487             // datepicker element
36488             datepickerEl = angular.element(popupEl.children()[0]);
36489             datepickerEl.attr('template-url', datepickerTemplateUrl);
36490
36491             if (isHtml5DateInput) {
36492               if (attrs.type === 'month') {
36493                 datepickerEl.attr('datepicker-mode', '"month"');
36494                 datepickerEl.attr('min-mode', 'month');
36495               }
36496             }
36497
36498             if (attrs.datepickerOptions) {
36499               var options = scope.$parent.$eval(attrs.datepickerOptions);
36500               if (options && options.initDate) {
36501                 scope.initDate = dateParser.fromTimezone(options.initDate, ngModelOptions.timezone);
36502                 datepickerEl.attr('init-date', 'initDate');
36503                 delete options.initDate;
36504               }
36505               angular.forEach(options, function(value, option) {
36506                 datepickerEl.attr(cameltoDash(option), value);
36507               });
36508             }
36509
36510             angular.forEach(['minMode', 'maxMode'], function(key) {
36511               if (attrs[key]) {
36512                 scope.$parent.$watch(function() { return attrs[key]; }, function(value) {
36513                   scope.watchData[key] = value;
36514                 });
36515                 datepickerEl.attr(cameltoDash(key), 'watchData.' + key);
36516               }
36517             });
36518
36519             angular.forEach(['datepickerMode', 'shortcutPropagation'], function(key) {
36520               if (attrs[key]) {
36521                 var getAttribute = $parse(attrs[key]);
36522                 var propConfig = {
36523                   get: function() {
36524                     return getAttribute(scope.$parent);
36525                   }
36526                 };
36527
36528                 datepickerEl.attr(cameltoDash(key), 'watchData.' + key);
36529
36530                 // Propagate changes from datepicker to outside
36531                 if (key === 'datepickerMode') {
36532                   var setAttribute = getAttribute.assign;
36533                   propConfig.set = function(v) {
36534                     setAttribute(scope.$parent, v);
36535                   };
36536                 }
36537
36538                 Object.defineProperty(scope.watchData, key, propConfig);
36539               }
36540             });
36541
36542             angular.forEach(['minDate', 'maxDate', 'initDate'], function(key) {
36543               if (attrs[key]) {
36544                 var getAttribute = $parse(attrs[key]);
36545
36546                 scope.$parent.$watch(getAttribute, function(value) {
36547                   if (key === 'minDate' || key === 'maxDate') {
36548                     cache[key] = angular.isDate(value) ? dateParser.fromTimezone(new Date(value), ngModelOptions.timezone) : new Date(dateFilter(value, 'medium'));
36549                   }
36550
36551                   scope.watchData[key] = cache[key] || dateParser.fromTimezone(new Date(value), ngModelOptions.timezone);
36552                 });
36553
36554                 datepickerEl.attr(cameltoDash(key), 'watchData.' + key);
36555               }
36556             });
36557
36558             if (attrs.dateDisabled) {
36559               datepickerEl.attr('date-disabled', 'dateDisabled({ date: date, mode: mode })');
36560             }
36561
36562             angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle', 'showWeeks', 'startingDay', 'yearRows', 'yearColumns'], function(key) {
36563               if (angular.isDefined(attrs[key])) {
36564                 datepickerEl.attr(cameltoDash(key), attrs[key]);
36565               }
36566             });
36567
36568             if (attrs.customClass) {
36569               datepickerEl.attr('custom-class', 'customClass({ date: date, mode: mode })');
36570             }
36571
36572             if (!isHtml5DateInput) {
36573               // Internal API to maintain the correct ng-invalid-[key] class
36574               ngModel.$$parserName = 'date';
36575               ngModel.$validators.date = validator;
36576               ngModel.$parsers.unshift(parseDate);
36577               ngModel.$formatters.push(function(value) {
36578                 if (ngModel.$isEmpty(value)) {
36579                   scope.date = value;
36580                   return value;
36581                 }
36582                 scope.date = dateParser.fromTimezone(value, ngModelOptions.timezone);
36583                 return dateFilter(scope.date, dateFormat);
36584               });
36585             } else {
36586               ngModel.$formatters.push(function(value) {
36587                 scope.date = dateParser.fromTimezone(value, ngModelOptions.timezone);
36588                 return value;
36589               });
36590             }
36591
36592             // Detect changes in the view from the text box
36593             ngModel.$viewChangeListeners.push(function() {
36594               scope.date = parseDateString(ngModel.$viewValue);
36595             });
36596
36597             element.bind('keydown', inputKeydownBind);
36598
36599             $popup = $compile(popupEl)(scope);
36600             // Prevent jQuery cache memory leak (template is now redundant after linking)
36601             popupEl.remove();
36602
36603             if (appendToBody) {
36604               $document.find('body').append($popup);
36605             } else {
36606               element.after($popup);
36607             }
36608
36609             scope.$on('$destroy', function() {
36610               if (scope.isOpen === true) {
36611                 if (!$rootScope.$$phase) {
36612                   scope.$apply(function() {
36613                     scope.isOpen = false;
36614                   });
36615                 }
36616               }
36617
36618               $popup.remove();
36619               element.unbind('keydown', inputKeydownBind);
36620               $document.unbind('click', documentClickBind);
36621             });
36622           };
36623
36624           scope.getText = function(key) {
36625             return scope[key + 'Text'] || datepickerPopupConfig[key + 'Text'];
36626           };
36627
36628           scope.isDisabled = function(date) {
36629             if (date === 'today') {
36630               date = new Date();
36631             }
36632
36633             return scope.watchData.minDate && scope.compare(date, cache.minDate) < 0 ||
36634               scope.watchData.maxDate && scope.compare(date, cache.maxDate) > 0;
36635           };
36636
36637           scope.compare = function(date1, date2) {
36638             return new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
36639           };
36640
36641           // Inner change
36642           scope.dateSelection = function(dt) {
36643             if (angular.isDefined(dt)) {
36644               scope.date = dt;
36645             }
36646             var date = scope.date ? dateFilter(scope.date, dateFormat) : null; // Setting to NULL is necessary for form validators to function
36647             element.val(date);
36648             ngModel.$setViewValue(date);
36649
36650             if (closeOnDateSelection) {
36651               scope.isOpen = false;
36652               element[0].focus();
36653             }
36654           };
36655
36656           scope.keydown = function(evt) {
36657             if (evt.which === 27) {
36658               evt.stopPropagation();
36659               scope.isOpen = false;
36660               element[0].focus();
36661             }
36662           };
36663
36664           scope.select = function(date) {
36665             if (date === 'today') {
36666               var today = new Date();
36667               if (angular.isDate(scope.date)) {
36668                 date = new Date(scope.date);
36669                 date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate());
36670               } else {
36671                 date = new Date(today.setHours(0, 0, 0, 0));
36672               }
36673             }
36674             scope.dateSelection(date);
36675           };
36676
36677           scope.close = function() {
36678             scope.isOpen = false;
36679             element[0].focus();
36680           };
36681
36682           scope.disabled = angular.isDefined(attrs.disabled) || false;
36683           if (attrs.ngDisabled) {
36684             scope.$parent.$watch($parse(attrs.ngDisabled), function(disabled) {
36685               scope.disabled = disabled;
36686             });
36687           }
36688
36689           scope.$watch('isOpen', function(value) {
36690             if (value) {
36691               if (!scope.disabled) {
36692                 scope.position = appendToBody ? $position.offset(element) : $position.position(element);
36693                 scope.position.top = scope.position.top + element.prop('offsetHeight');
36694
36695                 $timeout(function() {
36696                   if (onOpenFocus) {
36697                     scope.$broadcast('uib:datepicker.focus');
36698                   }
36699                   $document.bind('click', documentClickBind);
36700                 }, 0, false);
36701               } else {
36702                 scope.isOpen = false;
36703               }
36704             } else {
36705               $document.unbind('click', documentClickBind);
36706             }
36707           });
36708
36709           function cameltoDash(string) {
36710             return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); });
36711           }
36712
36713           function parseDateString(viewValue) {
36714             var date = dateParser.parse(viewValue, dateFormat, scope.date);
36715             if (isNaN(date)) {
36716               for (var i = 0; i < altInputFormats.length; i++) {
36717                 date = dateParser.parse(viewValue, altInputFormats[i], scope.date);
36718                 if (!isNaN(date)) {
36719                   return date;
36720                 }
36721               }
36722             }
36723             return date;
36724           }
36725
36726           function parseDate(viewValue) {
36727             if (angular.isNumber(viewValue)) {
36728               // presumably timestamp to date object
36729               viewValue = new Date(viewValue);
36730             }
36731
36732             if (!viewValue) {
36733               return null;
36734             }
36735
36736             if (angular.isDate(viewValue) && !isNaN(viewValue)) {
36737               return viewValue;
36738             }
36739
36740             if (angular.isString(viewValue)) {
36741               var date = parseDateString(viewValue);
36742               if (!isNaN(date)) {
36743                 return dateParser.toTimezone(date, ngModelOptions.timezone);
36744               }
36745             }
36746
36747             return ngModel.$options && ngModel.$options.allowInvalid ? viewValue : undefined;
36748           }
36749
36750           function validator(modelValue, viewValue) {
36751             var value = modelValue || viewValue;
36752
36753             if (!attrs.ngRequired && !value) {
36754               return true;
36755             }
36756
36757             if (angular.isNumber(value)) {
36758               value = new Date(value);
36759             }
36760
36761             if (!value) {
36762               return true;
36763             }
36764
36765             if (angular.isDate(value) && !isNaN(value)) {
36766               return true;
36767             }
36768
36769             if (angular.isString(value)) {
36770               return !isNaN(parseDateString(viewValue));
36771             }
36772
36773             return false;
36774           }
36775
36776           function documentClickBind(event) {
36777             if (!scope.isOpen && scope.disabled) {
36778               return;
36779             }
36780
36781             var popup = $popup[0];
36782             var dpContainsTarget = element[0].contains(event.target);
36783             // The popup node may not be an element node
36784             // In some browsers (IE) only element nodes have the 'contains' function
36785             var popupContainsTarget = popup.contains !== undefined && popup.contains(event.target);
36786             if (scope.isOpen && !(dpContainsTarget || popupContainsTarget)) {
36787               scope.$apply(function() {
36788                 scope.isOpen = false;
36789               });
36790             }
36791           }
36792
36793           function inputKeydownBind(evt) {
36794             if (evt.which === 27 && scope.isOpen) {
36795               evt.preventDefault();
36796               evt.stopPropagation();
36797               scope.$apply(function() {
36798                 scope.isOpen = false;
36799               });
36800               element[0].focus();
36801             } else if (evt.which === 40 && !scope.isOpen) {
36802               evt.preventDefault();
36803               evt.stopPropagation();
36804               scope.$apply(function() {
36805                 scope.isOpen = true;
36806               });
36807             }
36808           }
36809         }])
36810
36811         .directive('uibDatepickerPopup', function() {
36812           return {
36813             require: ['ngModel', 'uibDatepickerPopup'],
36814             controller: 'UibDatepickerPopupController',
36815             scope: {
36816               isOpen: '=?',
36817               currentText: '@',
36818               clearText: '@',
36819               closeText: '@',
36820               dateDisabled: '&',
36821               customClass: '&'
36822             },
36823             link: function(scope, element, attrs, ctrls) {
36824               var ngModel = ctrls[0],
36825                 ctrl = ctrls[1];
36826
36827               ctrl.init(ngModel);
36828             }
36829           };
36830         })
36831
36832         .directive('uibDatepickerPopupWrap', function() {
36833           return {
36834             replace: true,
36835             transclude: true,
36836             templateUrl: function(element, attrs) {
36837               return attrs.templateUrl || 'uib/template/datepicker/popup.html';
36838             }
36839           };
36840         });
36841
36842         angular.module('ui.bootstrap.debounce', [])
36843         /**
36844          * A helper, internal service that debounces a function
36845          */
36846           .factory('$$debounce', ['$timeout', function($timeout) {
36847             return function(callback, debounceTime) {
36848               var timeoutPromise;
36849
36850               return function() {
36851                 var self = this;
36852                 var args = Array.prototype.slice.call(arguments);
36853                 if (timeoutPromise) {
36854                   $timeout.cancel(timeoutPromise);
36855                 }
36856
36857                 timeoutPromise = $timeout(function() {
36858                   callback.apply(self, args);
36859                 }, debounceTime);
36860               };
36861             };
36862           }]);
36863
36864         angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
36865
36866         .constant('uibDropdownConfig', {
36867           appendToOpenClass: 'uib-dropdown-open',
36868           openClass: 'open'
36869         })
36870
36871         .service('uibDropdownService', ['$document', '$rootScope', function($document, $rootScope) {
36872           var openScope = null;
36873
36874           this.open = function(dropdownScope) {
36875             if (!openScope) {
36876               $document.on('click', closeDropdown);
36877               $document.on('keydown', keybindFilter);
36878             }
36879
36880             if (openScope && openScope !== dropdownScope) {
36881               openScope.isOpen = false;
36882             }
36883
36884             openScope = dropdownScope;
36885           };
36886
36887           this.close = function(dropdownScope) {
36888             if (openScope === dropdownScope) {
36889               openScope = null;
36890               $document.off('click', closeDropdown);
36891               $document.off('keydown', keybindFilter);
36892             }
36893           };
36894
36895           var closeDropdown = function(evt) {
36896             // This method may still be called during the same mouse event that
36897             // unbound this event handler. So check openScope before proceeding.
36898             if (!openScope) { return; }
36899
36900             if (evt && openScope.getAutoClose() === 'disabled') { return; }
36901
36902             if (evt && evt.which === 3) { return; }
36903
36904             var toggleElement = openScope.getToggleElement();
36905             if (evt && toggleElement && toggleElement[0].contains(evt.target)) {
36906               return;
36907             }
36908
36909             var dropdownElement = openScope.getDropdownElement();
36910             if (evt && openScope.getAutoClose() === 'outsideClick' &&
36911               dropdownElement && dropdownElement[0].contains(evt.target)) {
36912               return;
36913             }
36914
36915             openScope.isOpen = false;
36916
36917             if (!$rootScope.$$phase) {
36918               openScope.$apply();
36919             }
36920           };
36921
36922           var keybindFilter = function(evt) {
36923             if (evt.which === 27) {
36924               openScope.focusToggleElement();
36925               closeDropdown();
36926             } else if (openScope.isKeynavEnabled() && [38, 40].indexOf(evt.which) !== -1 && openScope.isOpen) {
36927               evt.preventDefault();
36928               evt.stopPropagation();
36929               openScope.focusDropdownEntry(evt.which);
36930             }
36931           };
36932         }])
36933
36934         .controller('UibDropdownController', ['$scope', '$element', '$attrs', '$parse', 'uibDropdownConfig', 'uibDropdownService', '$animate', '$uibPosition', '$document', '$compile', '$templateRequest', function($scope, $element, $attrs, $parse, dropdownConfig, uibDropdownService, $animate, $position, $document, $compile, $templateRequest) {
36935           var self = this,
36936             scope = $scope.$new(), // create a child scope so we are not polluting original one
36937             templateScope,
36938             appendToOpenClass = dropdownConfig.appendToOpenClass,
36939             openClass = dropdownConfig.openClass,
36940             getIsOpen,
36941             setIsOpen = angular.noop,
36942             toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop,
36943             appendToBody = false,
36944             appendTo = null,
36945             keynavEnabled = false,
36946             selectedOption = null,
36947             body = $document.find('body');
36948
36949           $element.addClass('dropdown');
36950
36951           this.init = function() {
36952             if ($attrs.isOpen) {
36953               getIsOpen = $parse($attrs.isOpen);
36954               setIsOpen = getIsOpen.assign;
36955
36956               $scope.$watch(getIsOpen, function(value) {
36957                 scope.isOpen = !!value;
36958               });
36959             }
36960
36961             if (angular.isDefined($attrs.dropdownAppendTo)) {
36962               var appendToEl = $parse($attrs.dropdownAppendTo)(scope);
36963               if (appendToEl) {
36964                 appendTo = angular.element(appendToEl);
36965               }
36966             }
36967
36968             appendToBody = angular.isDefined($attrs.dropdownAppendToBody);
36969             keynavEnabled = angular.isDefined($attrs.keyboardNav);
36970
36971             if (appendToBody && !appendTo) {
36972               appendTo = body;
36973             }
36974
36975             if (appendTo && self.dropdownMenu) {
36976               appendTo.append(self.dropdownMenu);
36977               $element.on('$destroy', function handleDestroyEvent() {
36978                 self.dropdownMenu.remove();
36979               });
36980             }
36981           };
36982
36983           this.toggle = function(open) {
36984             return scope.isOpen = arguments.length ? !!open : !scope.isOpen;
36985           };
36986
36987           // Allow other directives to watch status
36988           this.isOpen = function() {
36989             return scope.isOpen;
36990           };
36991
36992           scope.getToggleElement = function() {
36993             return self.toggleElement;
36994           };
36995
36996           scope.getAutoClose = function() {
36997             return $attrs.autoClose || 'always'; //or 'outsideClick' or 'disabled'
36998           };
36999
37000           scope.getElement = function() {
37001             return $element;
37002           };
37003
37004           scope.isKeynavEnabled = function() {
37005             return keynavEnabled;
37006           };
37007
37008           scope.focusDropdownEntry = function(keyCode) {
37009             var elems = self.dropdownMenu ? //If append to body is used.
37010               angular.element(self.dropdownMenu).find('a') :
37011               $element.find('ul').eq(0).find('a');
37012
37013             switch (keyCode) {
37014               case 40: {
37015                 if (!angular.isNumber(self.selectedOption)) {
37016                   self.selectedOption = 0;
37017                 } else {
37018                   self.selectedOption = self.selectedOption === elems.length - 1 ?
37019                     self.selectedOption :
37020                     self.selectedOption + 1;
37021                 }
37022                 break;
37023               }
37024               case 38: {
37025                 if (!angular.isNumber(self.selectedOption)) {
37026                   self.selectedOption = elems.length - 1;
37027                 } else {
37028                   self.selectedOption = self.selectedOption === 0 ?
37029                     0 : self.selectedOption - 1;
37030                 }
37031                 break;
37032               }
37033             }
37034             elems[self.selectedOption].focus();
37035           };
37036
37037           scope.getDropdownElement = function() {
37038             return self.dropdownMenu;
37039           };
37040
37041           scope.focusToggleElement = function() {
37042             if (self.toggleElement) {
37043               self.toggleElement[0].focus();
37044             }
37045           };
37046
37047           scope.$watch('isOpen', function(isOpen, wasOpen) {
37048             if (appendTo && self.dropdownMenu) {
37049               var pos = $position.positionElements($element, self.dropdownMenu, 'bottom-left', true),
37050                 css,
37051                 rightalign;
37052
37053               css = {
37054                 top: pos.top + 'px',
37055                 display: isOpen ? 'block' : 'none'
37056               };
37057
37058               rightalign = self.dropdownMenu.hasClass('dropdown-menu-right');
37059               if (!rightalign) {
37060                 css.left = pos.left + 'px';
37061                 css.right = 'auto';
37062               } else {
37063                 css.left = 'auto';
37064                 css.right = window.innerWidth -
37065                   (pos.left + $element.prop('offsetWidth')) + 'px';
37066               }
37067
37068               // Need to adjust our positioning to be relative to the appendTo container
37069               // if it's not the body element
37070               if (!appendToBody) {
37071                 var appendOffset = $position.offset(appendTo);
37072
37073                 css.top = pos.top - appendOffset.top + 'px';
37074
37075                 if (!rightalign) {
37076                   css.left = pos.left - appendOffset.left + 'px';
37077                 } else {
37078                   css.right = window.innerWidth -
37079                     (pos.left - appendOffset.left + $element.prop('offsetWidth')) + 'px';
37080                 }
37081               }
37082
37083               self.dropdownMenu.css(css);
37084             }
37085
37086             var openContainer = appendTo ? appendTo : $element;
37087
37088             $animate[isOpen ? 'addClass' : 'removeClass'](openContainer, appendTo ? appendToOpenClass : openClass).then(function() {
37089               if (angular.isDefined(isOpen) && isOpen !== wasOpen) {
37090                 toggleInvoker($scope, { open: !!isOpen });
37091               }
37092             });
37093
37094             if (isOpen) {
37095               if (self.dropdownMenuTemplateUrl) {
37096                 $templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) {
37097                   templateScope = scope.$new();
37098                   $compile(tplContent.trim())(templateScope, function(dropdownElement) {
37099                     var newEl = dropdownElement;
37100                     self.dropdownMenu.replaceWith(newEl);
37101                     self.dropdownMenu = newEl;
37102                   });
37103                 });
37104               }
37105
37106               scope.focusToggleElement();
37107               uibDropdownService.open(scope);
37108             } else {
37109               if (self.dropdownMenuTemplateUrl) {
37110                 if (templateScope) {
37111                   templateScope.$destroy();
37112                 }
37113                 var newEl = angular.element('<ul class="dropdown-menu"></ul>');
37114                 self.dropdownMenu.replaceWith(newEl);
37115                 self.dropdownMenu = newEl;
37116               }
37117
37118               uibDropdownService.close(scope);
37119               self.selectedOption = null;
37120             }
37121
37122             if (angular.isFunction(setIsOpen)) {
37123               setIsOpen($scope, isOpen);
37124             }
37125           });
37126
37127           $scope.$on('$locationChangeSuccess', function() {
37128             if (scope.getAutoClose() !== 'disabled') {
37129               scope.isOpen = false;
37130             }
37131           });
37132         }])
37133
37134         .directive('uibDropdown', function() {
37135           return {
37136             controller: 'UibDropdownController',
37137             link: function(scope, element, attrs, dropdownCtrl) {
37138               dropdownCtrl.init();
37139             }
37140           };
37141         })
37142
37143         .directive('uibDropdownMenu', function() {
37144           return {
37145             restrict: 'A',
37146             require: '?^uibDropdown',
37147             link: function(scope, element, attrs, dropdownCtrl) {
37148               if (!dropdownCtrl || angular.isDefined(attrs.dropdownNested)) {
37149                 return;
37150               }
37151
37152               element.addClass('dropdown-menu');
37153
37154               var tplUrl = attrs.templateUrl;
37155               if (tplUrl) {
37156                 dropdownCtrl.dropdownMenuTemplateUrl = tplUrl;
37157               }
37158
37159               if (!dropdownCtrl.dropdownMenu) {
37160                 dropdownCtrl.dropdownMenu = element;
37161               }
37162             }
37163           };
37164         })
37165
37166         .directive('uibDropdownToggle', function() {
37167           return {
37168             require: '?^uibDropdown',
37169             link: function(scope, element, attrs, dropdownCtrl) {
37170               if (!dropdownCtrl) {
37171                 return;
37172               }
37173
37174               element.addClass('dropdown-toggle');
37175
37176               dropdownCtrl.toggleElement = element;
37177
37178               var toggleDropdown = function(event) {
37179                 event.preventDefault();
37180
37181                 if (!element.hasClass('disabled') && !attrs.disabled) {
37182                   scope.$apply(function() {
37183                     dropdownCtrl.toggle();
37184                   });
37185                 }
37186               };
37187
37188               element.bind('click', toggleDropdown);
37189
37190               // WAI-ARIA
37191               element.attr({ 'aria-haspopup': true, 'aria-expanded': false });
37192               scope.$watch(dropdownCtrl.isOpen, function(isOpen) {
37193                 element.attr('aria-expanded', !!isOpen);
37194               });
37195
37196               scope.$on('$destroy', function() {
37197                 element.unbind('click', toggleDropdown);
37198               });
37199             }
37200           };
37201         });
37202
37203         angular.module('ui.bootstrap.stackedMap', [])
37204         /**
37205          * A helper, internal data structure that acts as a map but also allows getting / removing
37206          * elements in the LIFO order
37207          */
37208           .factory('$$stackedMap', function() {
37209             return {
37210               createNew: function() {
37211                 var stack = [];
37212
37213                 return {
37214                   add: function(key, value) {
37215                     stack.push({
37216                       key: key,
37217                       value: value
37218                     });
37219                   },
37220                   get: function(key) {
37221                     for (var i = 0; i < stack.length; i++) {
37222                       if (key === stack[i].key) {
37223                         return stack[i];
37224                       }
37225                     }
37226                   },
37227                   keys: function() {
37228                     var keys = [];
37229                     for (var i = 0; i < stack.length; i++) {
37230                       keys.push(stack[i].key);
37231                     }
37232                     return keys;
37233                   },
37234                   top: function() {
37235                     return stack[stack.length - 1];
37236                   },
37237                   remove: function(key) {
37238                     var idx = -1;
37239                     for (var i = 0; i < stack.length; i++) {
37240                       if (key === stack[i].key) {
37241                         idx = i;
37242                         break;
37243                       }
37244                     }
37245                     return stack.splice(idx, 1)[0];
37246                   },
37247                   removeTop: function() {
37248                     return stack.splice(stack.length - 1, 1)[0];
37249                   },
37250                   length: function() {
37251                     return stack.length;
37252                   }
37253                 };
37254               }
37255             };
37256           });
37257         angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
37258         /**
37259          * A helper, internal data structure that stores all references attached to key
37260          */
37261           .factory('$$multiMap', function() {
37262             return {
37263               createNew: function() {
37264                 var map = {};
37265
37266                 return {
37267                   entries: function() {
37268                     return Object.keys(map).map(function(key) {
37269                       return {
37270                         key: key,
37271                         value: map[key]
37272                       };
37273                     });
37274                   },
37275                   get: function(key) {
37276                     return map[key];
37277                   },
37278                   hasKey: function(key) {
37279                     return !!map[key];
37280                   },
37281                   keys: function() {
37282                     return Object.keys(map);
37283                   },
37284                   put: function(key, value) {
37285                     if (!map[key]) {
37286                       map[key] = [];
37287                     }
37288
37289                     map[key].push(value);
37290                   },
37291                   remove: function(key, value) {
37292                     var values = map[key];
37293
37294                     if (!values) {
37295                       return;
37296                     }
37297
37298                     var idx = values.indexOf(value);
37299
37300                     if (idx !== -1) {
37301                       values.splice(idx, 1);
37302                     }
37303
37304                     if (!values.length) {
37305                       delete map[key];
37306                     }
37307                   }
37308                 };
37309               }
37310             };
37311           })
37312
37313         /**
37314          * Pluggable resolve mechanism for the modal resolve resolution
37315          * Supports UI Router's $resolve service
37316          */
37317           .provider('$uibResolve', function() {
37318             var resolve = this;
37319             this.resolver = null;
37320
37321             this.setResolver = function(resolver) {
37322               this.resolver = resolver;
37323             };
37324
37325             this.$get = ['$injector', '$q', function($injector, $q) {
37326               var resolver = resolve.resolver ? $injector.get(resolve.resolver) : null;
37327               return {
37328                 resolve: function(invocables, locals, parent, self) {
37329                   if (resolver) {
37330                     return resolver.resolve(invocables, locals, parent, self);
37331                   }
37332
37333                   var promises = [];
37334
37335                   angular.forEach(invocables, function(value) {
37336                     if (angular.isFunction(value) || angular.isArray(value)) {
37337                       promises.push($q.resolve($injector.invoke(value)));
37338                     } else if (angular.isString(value)) {
37339                       promises.push($q.resolve($injector.get(value)));
37340                     } else {
37341                       promises.push($q.resolve(value));
37342                     }
37343                   });
37344
37345                   return $q.all(promises).then(function(resolves) {
37346                     var resolveObj = {};
37347                     var resolveIter = 0;
37348                     angular.forEach(invocables, function(value, key) {
37349                       resolveObj[key] = resolves[resolveIter++];
37350                     });
37351
37352                     return resolveObj;
37353                   });
37354                 }
37355               };
37356             }];
37357           })
37358
37359         /**
37360          * A helper directive for the $modal service. It creates a backdrop element.
37361          */
37362           .directive('uibModalBackdrop', ['$animateCss', '$injector', '$uibModalStack',
37363           function($animateCss, $injector, $modalStack) {
37364             return {
37365               replace: true,
37366               templateUrl: 'uib/template/modal/backdrop.html',
37367               compile: function(tElement, tAttrs) {
37368                 tElement.addClass(tAttrs.backdropClass);
37369                 return linkFn;
37370               }
37371             };
37372
37373             function linkFn(scope, element, attrs) {
37374               if (attrs.modalInClass) {
37375                 $animateCss(element, {
37376                   addClass: attrs.modalInClass
37377                 }).start();
37378
37379                 scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
37380                   var done = setIsAsync();
37381                   if (scope.modalOptions.animation) {
37382                     $animateCss(element, {
37383                       removeClass: attrs.modalInClass
37384                     }).start().then(done);
37385                   } else {
37386                     done();
37387                   }
37388                 });
37389               }
37390             }
37391           }])
37392
37393           .directive('uibModalWindow', ['$uibModalStack', '$q', '$animate', '$animateCss', '$document',
37394           function($modalStack, $q, $animate, $animateCss, $document) {
37395             return {
37396               scope: {
37397                 index: '@'
37398               },
37399               replace: true,
37400               transclude: true,
37401               templateUrl: function(tElement, tAttrs) {
37402                 return tAttrs.templateUrl || 'uib/template/modal/window.html';
37403               },
37404               link: function(scope, element, attrs) {
37405                 element.addClass(attrs.windowClass || '');
37406                 element.addClass(attrs.windowTopClass || '');
37407                 scope.size = attrs.size;
37408
37409                 scope.close = function(evt) {
37410                   var modal = $modalStack.getTop();
37411                   if (modal && modal.value.backdrop &&
37412                     modal.value.backdrop !== 'static' &&
37413                     evt.target === evt.currentTarget) {
37414                     evt.preventDefault();
37415                     evt.stopPropagation();
37416                     $modalStack.dismiss(modal.key, 'backdrop click');
37417                   }
37418                 };
37419
37420                 // moved from template to fix issue #2280
37421                 element.on('click', scope.close);
37422
37423                 // This property is only added to the scope for the purpose of detecting when this directive is rendered.
37424                 // We can detect that by using this property in the template associated with this directive and then use
37425                 // {@link Attribute#$observe} on it. For more details please see {@link TableColumnResize}.
37426                 scope.$isRendered = true;
37427
37428                 // Deferred object that will be resolved when this modal is render.
37429                 var modalRenderDeferObj = $q.defer();
37430                 // Observe function will be called on next digest cycle after compilation, ensuring that the DOM is ready.
37431                 // In order to use this way of finding whether DOM is ready, we need to observe a scope property used in modal's template.
37432                 attrs.$observe('modalRender', function(value) {
37433                   if (value === 'true') {
37434                     modalRenderDeferObj.resolve();
37435                   }
37436                 });
37437
37438                 modalRenderDeferObj.promise.then(function() {
37439                   var animationPromise = null;
37440
37441                   if (attrs.modalInClass) {
37442                     animationPromise = $animateCss(element, {
37443                       addClass: attrs.modalInClass
37444                     }).start();
37445
37446                     scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
37447                       var done = setIsAsync();
37448                       if ($animateCss) {
37449                         $animateCss(element, {
37450                           removeClass: attrs.modalInClass
37451                         }).start().then(done);
37452                       } else {
37453                         $animate.removeClass(element, attrs.modalInClass).then(done);
37454                       }
37455                     });
37456                   }
37457
37458
37459                   $q.when(animationPromise).then(function() {
37460                     /**
37461                      * If something within the freshly-opened modal already has focus (perhaps via a
37462                      * directive that causes focus). then no need to try and focus anything.
37463                      */
37464                     if (!($document[0].activeElement && element[0].contains($document[0].activeElement))) {
37465                       var inputWithAutofocus = element[0].querySelector('[autofocus]');
37466                       /**
37467                        * Auto-focusing of a freshly-opened modal element causes any child elements
37468                        * with the autofocus attribute to lose focus. This is an issue on touch
37469                        * based devices which will show and then hide the onscreen keyboard.
37470                        * Attempts to refocus the autofocus element via JavaScript will not reopen
37471                        * the onscreen keyboard. Fixed by updated the focusing logic to only autofocus
37472                        * the modal element if the modal does not contain an autofocus element.
37473                        */
37474                       if (inputWithAutofocus) {
37475                         inputWithAutofocus.focus();
37476                       } else {
37477                         element[0].focus();
37478                       }
37479                     }
37480                   });
37481
37482                   // Notify {@link $modalStack} that modal is rendered.
37483                   var modal = $modalStack.getTop();
37484                   if (modal) {
37485                     $modalStack.modalRendered(modal.key);
37486                   }
37487                 });
37488               }
37489             };
37490           }])
37491
37492           .directive('uibModalAnimationClass', function() {
37493             return {
37494               compile: function(tElement, tAttrs) {
37495                 if (tAttrs.modalAnimation) {
37496                   tElement.addClass(tAttrs.uibModalAnimationClass);
37497                 }
37498               }
37499             };
37500           })
37501
37502           .directive('uibModalTransclude', function() {
37503             return {
37504               link: function(scope, element, attrs, controller, transclude) {
37505                 transclude(scope.$parent, function(clone) {
37506                   element.empty();
37507                   element.append(clone);
37508                 });
37509               }
37510             };
37511           })
37512
37513           .factory('$uibModalStack', ['$animate', '$animateCss', '$document',
37514             '$compile', '$rootScope', '$q', '$$multiMap', '$$stackedMap',
37515             function($animate, $animateCss, $document, $compile, $rootScope, $q, $$multiMap, $$stackedMap) {
37516               var OPENED_MODAL_CLASS = 'modal-open';
37517
37518               var backdropDomEl, backdropScope;
37519               var openedWindows = $$stackedMap.createNew();
37520               var openedClasses = $$multiMap.createNew();
37521               var $modalStack = {
37522                 NOW_CLOSING_EVENT: 'modal.stack.now-closing'
37523               };
37524
37525               //Modal focus behavior
37526               var focusableElementList;
37527               var focusIndex = 0;
37528               var tababbleSelector = 'a[href], area[href], input:not([disabled]), ' +
37529                 'button:not([disabled]),select:not([disabled]), textarea:not([disabled]), ' +
37530                 'iframe, object, embed, *[tabindex], *[contenteditable=true]';
37531
37532               function backdropIndex() {
37533                 var topBackdropIndex = -1;
37534                 var opened = openedWindows.keys();
37535                 for (var i = 0; i < opened.length; i++) {
37536                   if (openedWindows.get(opened[i]).value.backdrop) {
37537                     topBackdropIndex = i;
37538                   }
37539                 }
37540                 return topBackdropIndex;
37541               }
37542
37543               $rootScope.$watch(backdropIndex, function(newBackdropIndex) {
37544                 if (backdropScope) {
37545                   backdropScope.index = newBackdropIndex;
37546                 }
37547               });
37548
37549               function removeModalWindow(modalInstance, elementToReceiveFocus) {
37550                 var modalWindow = openedWindows.get(modalInstance).value;
37551                 var appendToElement = modalWindow.appendTo;
37552
37553                 //clean up the stack
37554                 openedWindows.remove(modalInstance);
37555
37556                 removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
37557                   var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS;
37558                   openedClasses.remove(modalBodyClass, modalInstance);
37559                   appendToElement.toggleClass(modalBodyClass, openedClasses.hasKey(modalBodyClass));
37560                   toggleTopWindowClass(true);
37561                 });
37562                 checkRemoveBackdrop();
37563
37564                 //move focus to specified element if available, or else to body
37565                 if (elementToReceiveFocus && elementToReceiveFocus.focus) {
37566                   elementToReceiveFocus.focus();
37567                 } else if (appendToElement.focus) {
37568                   appendToElement.focus();
37569                 }
37570               }
37571
37572               // Add or remove "windowTopClass" from the top window in the stack
37573               function toggleTopWindowClass(toggleSwitch) {
37574                 var modalWindow;
37575
37576                 if (openedWindows.length() > 0) {
37577                   modalWindow = openedWindows.top().value;
37578                   modalWindow.modalDomEl.toggleClass(modalWindow.windowTopClass || '', toggleSwitch);
37579                 }
37580               }
37581
37582               function checkRemoveBackdrop() {
37583                 //remove backdrop if no longer needed
37584                 if (backdropDomEl && backdropIndex() === -1) {
37585                   var backdropScopeRef = backdropScope;
37586                   removeAfterAnimate(backdropDomEl, backdropScope, function() {
37587                     backdropScopeRef = null;
37588                   });
37589                   backdropDomEl = undefined;
37590                   backdropScope = undefined;
37591                 }
37592               }
37593
37594               function removeAfterAnimate(domEl, scope, done, closedDeferred) {
37595                 var asyncDeferred;
37596                 var asyncPromise = null;
37597                 var setIsAsync = function() {
37598                   if (!asyncDeferred) {
37599                     asyncDeferred = $q.defer();
37600                     asyncPromise = asyncDeferred.promise;
37601                   }
37602
37603                   return function asyncDone() {
37604                     asyncDeferred.resolve();
37605                   };
37606                 };
37607                 scope.$broadcast($modalStack.NOW_CLOSING_EVENT, setIsAsync);
37608
37609                 // Note that it's intentional that asyncPromise might be null.
37610                 // That's when setIsAsync has not been called during the
37611                 // NOW_CLOSING_EVENT broadcast.
37612                 return $q.when(asyncPromise).then(afterAnimating);
37613
37614                 function afterAnimating() {
37615                   if (afterAnimating.done) {
37616                     return;
37617                   }
37618                   afterAnimating.done = true;
37619
37620                   $animateCss(domEl, {
37621                     event: 'leave'
37622                   }).start().then(function() {
37623                     domEl.remove();
37624                     if (closedDeferred) {
37625                       closedDeferred.resolve();
37626                     }
37627                   });
37628
37629                   scope.$destroy();
37630                   if (done) {
37631                     done();
37632                   }
37633                 }
37634               }
37635
37636               $document.on('keydown', keydownListener);
37637
37638               $rootScope.$on('$destroy', function() {
37639                 $document.off('keydown', keydownListener);
37640               });
37641
37642               function keydownListener(evt) {
37643                 if (evt.isDefaultPrevented()) {
37644                   return evt;
37645                 }
37646
37647                 var modal = openedWindows.top();
37648                 if (modal) {
37649                   switch (evt.which) {
37650                     case 27: {
37651                       if (modal.value.keyboard) {
37652                         evt.preventDefault();
37653                         $rootScope.$apply(function() {
37654                           $modalStack.dismiss(modal.key, 'escape key press');
37655                         });
37656                       }
37657                       break;
37658                     }
37659                     case 9: {
37660                       $modalStack.loadFocusElementList(modal);
37661                       var focusChanged = false;
37662                       if (evt.shiftKey) {
37663                         if ($modalStack.isFocusInFirstItem(evt)) {
37664                           focusChanged = $modalStack.focusLastFocusableElement();
37665                         }
37666                       } else {
37667                         if ($modalStack.isFocusInLastItem(evt)) {
37668                           focusChanged = $modalStack.focusFirstFocusableElement();
37669                         }
37670                       }
37671
37672                       if (focusChanged) {
37673                         evt.preventDefault();
37674                         evt.stopPropagation();
37675                       }
37676                       break;
37677                     }
37678                   }
37679                 }
37680               }
37681
37682               $modalStack.open = function(modalInstance, modal) {
37683                 var modalOpener = $document[0].activeElement,
37684                   modalBodyClass = modal.openedClass || OPENED_MODAL_CLASS;
37685
37686                 toggleTopWindowClass(false);
37687
37688                 openedWindows.add(modalInstance, {
37689                   deferred: modal.deferred,
37690                   renderDeferred: modal.renderDeferred,
37691                   closedDeferred: modal.closedDeferred,
37692                   modalScope: modal.scope,
37693                   backdrop: modal.backdrop,
37694                   keyboard: modal.keyboard,
37695                   openedClass: modal.openedClass,
37696                   windowTopClass: modal.windowTopClass,
37697                   animation: modal.animation,
37698                   appendTo: modal.appendTo
37699                 });
37700
37701                 openedClasses.put(modalBodyClass, modalInstance);
37702
37703                 var appendToElement = modal.appendTo,
37704                     currBackdropIndex = backdropIndex();
37705
37706                 if (!appendToElement.length) {
37707                   throw new Error('appendTo element not found. Make sure that the element passed is in DOM.');
37708                 }
37709
37710                 if (currBackdropIndex >= 0 && !backdropDomEl) {
37711                   backdropScope = $rootScope.$new(true);
37712                   backdropScope.modalOptions = modal;
37713                   backdropScope.index = currBackdropIndex;
37714                   backdropDomEl = angular.element('<div uib-modal-backdrop="modal-backdrop"></div>');
37715                   backdropDomEl.attr('backdrop-class', modal.backdropClass);
37716                   if (modal.animation) {
37717                     backdropDomEl.attr('modal-animation', 'true');
37718                   }
37719                   $compile(backdropDomEl)(backdropScope);
37720                   $animate.enter(backdropDomEl, appendToElement);
37721                 }
37722
37723                 var angularDomEl = angular.element('<div uib-modal-window="modal-window"></div>');
37724                 angularDomEl.attr({
37725                   'template-url': modal.windowTemplateUrl,
37726                   'window-class': modal.windowClass,
37727                   'window-top-class': modal.windowTopClass,
37728                   'size': modal.size,
37729                   'index': openedWindows.length() - 1,
37730                   'animate': 'animate'
37731                 }).html(modal.content);
37732                 if (modal.animation) {
37733                   angularDomEl.attr('modal-animation', 'true');
37734                 }
37735
37736                 $animate.enter(angularDomEl, appendToElement)
37737                   .then(function() {
37738                     $compile(angularDomEl)(modal.scope);
37739                     $animate.addClass(appendToElement, modalBodyClass);
37740                   });
37741
37742                 openedWindows.top().value.modalDomEl = angularDomEl;
37743                 openedWindows.top().value.modalOpener = modalOpener;
37744
37745                 $modalStack.clearFocusListCache();
37746               };
37747
37748               function broadcastClosing(modalWindow, resultOrReason, closing) {
37749                 return !modalWindow.value.modalScope.$broadcast('modal.closing', resultOrReason, closing).defaultPrevented;
37750               }
37751
37752               $modalStack.close = function(modalInstance, result) {
37753                 var modalWindow = openedWindows.get(modalInstance);
37754                 if (modalWindow && broadcastClosing(modalWindow, result, true)) {
37755                   modalWindow.value.modalScope.$$uibDestructionScheduled = true;
37756                   modalWindow.value.deferred.resolve(result);
37757                   removeModalWindow(modalInstance, modalWindow.value.modalOpener);
37758                   return true;
37759                 }
37760                 return !modalWindow;
37761               };
37762
37763               $modalStack.dismiss = function(modalInstance, reason) {
37764                 var modalWindow = openedWindows.get(modalInstance);
37765                 if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
37766                   modalWindow.value.modalScope.$$uibDestructionScheduled = true;
37767                   modalWindow.value.deferred.reject(reason);
37768                   removeModalWindow(modalInstance, modalWindow.value.modalOpener);
37769                   return true;
37770                 }
37771                 return !modalWindow;
37772               };
37773
37774               $modalStack.dismissAll = function(reason) {
37775                 var topModal = this.getTop();
37776                 while (topModal && this.dismiss(topModal.key, reason)) {
37777                   topModal = this.getTop();
37778                 }
37779               };
37780
37781               $modalStack.getTop = function() {
37782                 return openedWindows.top();
37783               };
37784
37785               $modalStack.modalRendered = function(modalInstance) {
37786                 var modalWindow = openedWindows.get(modalInstance);
37787                 if (modalWindow) {
37788                   modalWindow.value.renderDeferred.resolve();
37789                 }
37790               };
37791
37792               $modalStack.focusFirstFocusableElement = function() {
37793                 if (focusableElementList.length > 0) {
37794                   focusableElementList[0].focus();
37795                   return true;
37796                 }
37797                 return false;
37798               };
37799               $modalStack.focusLastFocusableElement = function() {
37800                 if (focusableElementList.length > 0) {
37801                   focusableElementList[focusableElementList.length - 1].focus();
37802                   return true;
37803                 }
37804                 return false;
37805               };
37806
37807               $modalStack.isFocusInFirstItem = function(evt) {
37808                 if (focusableElementList.length > 0) {
37809                   return (evt.target || evt.srcElement) === focusableElementList[0];
37810                 }
37811                 return false;
37812               };
37813
37814               $modalStack.isFocusInLastItem = function(evt) {
37815                 if (focusableElementList.length > 0) {
37816                   return (evt.target || evt.srcElement) === focusableElementList[focusableElementList.length - 1];
37817                 }
37818                 return false;
37819               };
37820
37821               $modalStack.clearFocusListCache = function() {
37822                 focusableElementList = [];
37823                 focusIndex = 0;
37824               };
37825
37826               $modalStack.loadFocusElementList = function(modalWindow) {
37827                 if (focusableElementList === undefined || !focusableElementList.length) {
37828                   if (modalWindow) {
37829                     var modalDomE1 = modalWindow.value.modalDomEl;
37830                     if (modalDomE1 && modalDomE1.length) {
37831                       focusableElementList = modalDomE1[0].querySelectorAll(tababbleSelector);
37832                     }
37833                   }
37834                 }
37835               };
37836
37837               return $modalStack;
37838             }])
37839
37840           .provider('$uibModal', function() {
37841             var $modalProvider = {
37842               options: {
37843                 animation: true,
37844                 backdrop: true, //can also be false or 'static'
37845                 keyboard: true
37846               },
37847               $get: ['$rootScope', '$q', '$document', '$templateRequest', '$controller', '$uibResolve', '$uibModalStack',
37848                 function ($rootScope, $q, $document, $templateRequest, $controller, $uibResolve, $modalStack) {
37849                   var $modal = {};
37850
37851                   function getTemplatePromise(options) {
37852                     return options.template ? $q.when(options.template) :
37853                       $templateRequest(angular.isFunction(options.templateUrl) ?
37854                         options.templateUrl() : options.templateUrl);
37855                   }
37856
37857                   var promiseChain = null;
37858                   $modal.getPromiseChain = function() {
37859                     return promiseChain;
37860                   };
37861
37862                   $modal.open = function(modalOptions) {
37863                     var modalResultDeferred = $q.defer();
37864                     var modalOpenedDeferred = $q.defer();
37865                     var modalClosedDeferred = $q.defer();
37866                     var modalRenderDeferred = $q.defer();
37867
37868                     //prepare an instance of a modal to be injected into controllers and returned to a caller
37869                     var modalInstance = {
37870                       result: modalResultDeferred.promise,
37871                       opened: modalOpenedDeferred.promise,
37872                       closed: modalClosedDeferred.promise,
37873                       rendered: modalRenderDeferred.promise,
37874                       close: function (result) {
37875                         return $modalStack.close(modalInstance, result);
37876                       },
37877                       dismiss: function (reason) {
37878                         return $modalStack.dismiss(modalInstance, reason);
37879                       }
37880                     };
37881
37882                     //merge and clean up options
37883                     modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
37884                     modalOptions.resolve = modalOptions.resolve || {};
37885                     modalOptions.appendTo = modalOptions.appendTo || $document.find('body').eq(0);
37886
37887                     //verify options
37888                     if (!modalOptions.template && !modalOptions.templateUrl) {
37889                       throw new Error('One of template or templateUrl options is required.');
37890                     }
37891
37892                     var templateAndResolvePromise =
37893                       $q.all([getTemplatePromise(modalOptions), $uibResolve.resolve(modalOptions.resolve, {}, null, null)]);
37894
37895                     function resolveWithTemplate() {
37896                       return templateAndResolvePromise;
37897                     }
37898
37899                     // Wait for the resolution of the existing promise chain.
37900                     // Then switch to our own combined promise dependency (regardless of how the previous modal fared).
37901                     // Then add to $modalStack and resolve opened.
37902                     // Finally clean up the chain variable if no subsequent modal has overwritten it.
37903                     var samePromise;
37904                     samePromise = promiseChain = $q.all([promiseChain])
37905                       .then(resolveWithTemplate, resolveWithTemplate)
37906                       .then(function resolveSuccess(tplAndVars) {
37907                         var providedScope = modalOptions.scope || $rootScope;
37908
37909                         var modalScope = providedScope.$new();
37910                         modalScope.$close = modalInstance.close;
37911                         modalScope.$dismiss = modalInstance.dismiss;
37912
37913                         modalScope.$on('$destroy', function() {
37914                           if (!modalScope.$$uibDestructionScheduled) {
37915                             modalScope.$dismiss('$uibUnscheduledDestruction');
37916                           }
37917                         });
37918
37919                         var ctrlInstance, ctrlLocals = {};
37920
37921                         //controllers
37922                         if (modalOptions.controller) {
37923                           ctrlLocals.$scope = modalScope;
37924                           ctrlLocals.$uibModalInstance = modalInstance;
37925                           angular.forEach(tplAndVars[1], function(value, key) {
37926                             ctrlLocals[key] = value;
37927                           });
37928
37929                           ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
37930                           if (modalOptions.controllerAs) {
37931                             if (modalOptions.bindToController) {
37932                               ctrlInstance.$close = modalScope.$close;
37933                               ctrlInstance.$dismiss = modalScope.$dismiss;
37934                               angular.extend(ctrlInstance, providedScope);
37935                             }
37936
37937                             modalScope[modalOptions.controllerAs] = ctrlInstance;
37938                           }
37939                         }
37940
37941                         $modalStack.open(modalInstance, {
37942                           scope: modalScope,
37943                           deferred: modalResultDeferred,
37944                           renderDeferred: modalRenderDeferred,
37945                           closedDeferred: modalClosedDeferred,
37946                           content: tplAndVars[0],
37947                           animation: modalOptions.animation,
37948                           backdrop: modalOptions.backdrop,
37949                           keyboard: modalOptions.keyboard,
37950                           backdropClass: modalOptions.backdropClass,
37951                           windowTopClass: modalOptions.windowTopClass,
37952                           windowClass: modalOptions.windowClass,
37953                           windowTemplateUrl: modalOptions.windowTemplateUrl,
37954                           size: modalOptions.size,
37955                           openedClass: modalOptions.openedClass,
37956                           appendTo: modalOptions.appendTo
37957                         });
37958                         modalOpenedDeferred.resolve(true);
37959
37960                     }, function resolveError(reason) {
37961                       modalOpenedDeferred.reject(reason);
37962                       modalResultDeferred.reject(reason);
37963                     })['finally'](function() {
37964                       if (promiseChain === samePromise) {
37965                         promiseChain = null;
37966                       }
37967                     });
37968
37969                     return modalInstance;
37970                   };
37971
37972                   return $modal;
37973                 }
37974               ]
37975             };
37976
37977             return $modalProvider;
37978           });
37979
37980         angular.module('ui.bootstrap.paging', [])
37981         /**
37982          * Helper internal service for generating common controller code between the
37983          * pager and pagination components
37984          */
37985         .factory('uibPaging', ['$parse', function($parse) {
37986           return {
37987             create: function(ctrl, $scope, $attrs) {
37988               ctrl.setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
37989               ctrl.ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl
37990
37991               ctrl.init = function(ngModelCtrl, config) {
37992                 ctrl.ngModelCtrl = ngModelCtrl;
37993                 ctrl.config = config;
37994
37995                 ngModelCtrl.$render = function() {
37996                   ctrl.render();
37997                 };
37998
37999                 if ($attrs.itemsPerPage) {
38000                   $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
38001                     ctrl.itemsPerPage = parseInt(value, 10);
38002                     $scope.totalPages = ctrl.calculateTotalPages();
38003                     ctrl.updatePage();
38004                   });
38005                 } else {
38006                   ctrl.itemsPerPage = config.itemsPerPage;
38007                 }
38008
38009                 $scope.$watch('totalItems', function(newTotal, oldTotal) {
38010                   if (angular.isDefined(newTotal) || newTotal !== oldTotal) {
38011                     $scope.totalPages = ctrl.calculateTotalPages();
38012                     ctrl.updatePage();
38013                   }
38014                 });
38015               };
38016
38017               ctrl.calculateTotalPages = function() {
38018                 var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage);
38019                 return Math.max(totalPages || 0, 1);
38020               };
38021
38022               ctrl.render = function() {
38023                 $scope.page = parseInt(ctrl.ngModelCtrl.$viewValue, 10) || 1;
38024               };
38025
38026               $scope.selectPage = function(page, evt) {
38027                 if (evt) {
38028                   evt.preventDefault();
38029                 }
38030
38031                 var clickAllowed = !$scope.ngDisabled || !evt;
38032                 if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) {
38033                   if (evt && evt.target) {
38034                     evt.target.blur();
38035                   }
38036                   ctrl.ngModelCtrl.$setViewValue(page);
38037                   ctrl.ngModelCtrl.$render();
38038                 }
38039               };
38040
38041               $scope.getText = function(key) {
38042                 return $scope[key + 'Text'] || ctrl.config[key + 'Text'];
38043               };
38044
38045               $scope.noPrevious = function() {
38046                 return $scope.page === 1;
38047               };
38048
38049               $scope.noNext = function() {
38050                 return $scope.page === $scope.totalPages;
38051               };
38052
38053               ctrl.updatePage = function() {
38054                 ctrl.setNumPages($scope.$parent, $scope.totalPages); // Readonly variable
38055
38056                 if ($scope.page > $scope.totalPages) {
38057                   $scope.selectPage($scope.totalPages);
38058                 } else {
38059                   ctrl.ngModelCtrl.$render();
38060                 }
38061               };
38062             }
38063           };
38064         }]);
38065
38066         angular.module('ui.bootstrap.pager', ['ui.bootstrap.paging'])
38067
38068         .controller('UibPagerController', ['$scope', '$attrs', 'uibPaging', 'uibPagerConfig', function($scope, $attrs, uibPaging, uibPagerConfig) {
38069           $scope.align = angular.isDefined($attrs.align) ? $scope.$parent.$eval($attrs.align) : uibPagerConfig.align;
38070
38071           uibPaging.create(this, $scope, $attrs);
38072         }])
38073
38074         .constant('uibPagerConfig', {
38075           itemsPerPage: 10,
38076           previousText: '« Previous',
38077           nextText: 'Next »',
38078           align: true
38079         })
38080
38081         .directive('uibPager', ['uibPagerConfig', function(uibPagerConfig) {
38082           return {
38083             scope: {
38084               totalItems: '=',
38085               previousText: '@',
38086               nextText: '@',
38087               ngDisabled: '='
38088             },
38089             require: ['uibPager', '?ngModel'],
38090             controller: 'UibPagerController',
38091             controllerAs: 'pager',
38092             templateUrl: function(element, attrs) {
38093               return attrs.templateUrl || 'uib/template/pager/pager.html';
38094             },
38095             replace: true,
38096             link: function(scope, element, attrs, ctrls) {
38097               var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
38098
38099               if (!ngModelCtrl) {
38100                 return; // do nothing if no ng-model
38101               }
38102
38103               paginationCtrl.init(ngModelCtrl, uibPagerConfig);
38104             }
38105           };
38106         }]);
38107
38108         angular.module('ui.bootstrap.pagination', ['ui.bootstrap.paging'])
38109         .controller('UibPaginationController', ['$scope', '$attrs', '$parse', 'uibPaging', 'uibPaginationConfig', function($scope, $attrs, $parse, uibPaging, uibPaginationConfig) {
38110           var ctrl = this;
38111           // Setup configuration parameters
38112           var maxSize = angular.isDefined($attrs.maxSize) ? $scope.$parent.$eval($attrs.maxSize) : uibPaginationConfig.maxSize,
38113             rotate = angular.isDefined($attrs.rotate) ? $scope.$parent.$eval($attrs.rotate) : uibPaginationConfig.rotate,
38114             forceEllipses = angular.isDefined($attrs.forceEllipses) ? $scope.$parent.$eval($attrs.forceEllipses) : uibPaginationConfig.forceEllipses,
38115             boundaryLinkNumbers = angular.isDefined($attrs.boundaryLinkNumbers) ? $scope.$parent.$eval($attrs.boundaryLinkNumbers) : uibPaginationConfig.boundaryLinkNumbers;
38116           $scope.boundaryLinks = angular.isDefined($attrs.boundaryLinks) ? $scope.$parent.$eval($attrs.boundaryLinks) : uibPaginationConfig.boundaryLinks;
38117           $scope.directionLinks = angular.isDefined($attrs.directionLinks) ? $scope.$parent.$eval($attrs.directionLinks) : uibPaginationConfig.directionLinks;
38118
38119           uibPaging.create(this, $scope, $attrs);
38120
38121           if ($attrs.maxSize) {
38122             $scope.$parent.$watch($parse($attrs.maxSize), function(value) {
38123               maxSize = parseInt(value, 10);
38124               ctrl.render();
38125             });
38126           }
38127
38128           // Create page object used in template
38129           function makePage(number, text, isActive) {
38130             return {
38131               number: number,
38132               text: text,
38133               active: isActive
38134             };
38135           }
38136
38137           function getPages(currentPage, totalPages) {
38138             var pages = [];
38139
38140             // Default page limits
38141             var startPage = 1, endPage = totalPages;
38142             var isMaxSized = angular.isDefined(maxSize) && maxSize < totalPages;
38143
38144             // recompute if maxSize
38145             if (isMaxSized) {
38146               if (rotate) {
38147                 // Current page is displayed in the middle of the visible ones
38148                 startPage = Math.max(currentPage - Math.floor(maxSize / 2), 1);
38149                 endPage = startPage + maxSize - 1;
38150
38151                 // Adjust if limit is exceeded
38152                 if (endPage > totalPages) {
38153                   endPage = totalPages;
38154                   startPage = endPage - maxSize + 1;
38155                 }
38156               } else {
38157                 // Visible pages are paginated with maxSize
38158                 startPage = (Math.ceil(currentPage / maxSize) - 1) * maxSize + 1;
38159
38160                 // Adjust last page if limit is exceeded
38161                 endPage = Math.min(startPage + maxSize - 1, totalPages);
38162               }
38163             }
38164
38165             // Add page number links
38166             for (var number = startPage; number <= endPage; number++) {
38167               var page = makePage(number, number, number === currentPage);
38168               pages.push(page);
38169             }
38170
38171             // Add links to move between page sets
38172             if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) {
38173               if (startPage > 1) {
38174                 if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning
38175                 var previousPageSet = makePage(startPage - 1, '...', false);
38176                 pages.unshift(previousPageSet);
38177               }
38178                 if (boundaryLinkNumbers) {
38179                   if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential
38180                     var secondPageLink = makePage(2, '2', false);
38181                     pages.unshift(secondPageLink);
38182                   }
38183                   //add the first page
38184                   var firstPageLink = makePage(1, '1', false);
38185                   pages.unshift(firstPageLink);
38186                 }
38187               }
38188
38189               if (endPage < totalPages) {
38190                 if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end
38191                 var nextPageSet = makePage(endPage + 1, '...', false);
38192                 pages.push(nextPageSet);
38193               }
38194                 if (boundaryLinkNumbers) {
38195                   if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential
38196                     var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false);
38197                     pages.push(secondToLastPageLink);
38198                   }
38199                   //add the last page
38200                   var lastPageLink = makePage(totalPages, totalPages, false);
38201                   pages.push(lastPageLink);
38202                 }
38203               }
38204             }
38205             return pages;
38206           }
38207
38208           var originalRender = this.render;
38209           this.render = function() {
38210             originalRender();
38211             if ($scope.page > 0 && $scope.page <= $scope.totalPages) {
38212               $scope.pages = getPages($scope.page, $scope.totalPages);
38213             }
38214           };
38215         }])
38216
38217         .constant('uibPaginationConfig', {
38218           itemsPerPage: 10,
38219           boundaryLinks: false,
38220           boundaryLinkNumbers: false,
38221           directionLinks: true,
38222           firstText: 'First',
38223           previousText: 'Previous',
38224           nextText: 'Next',
38225           lastText: 'Last',
38226           rotate: true,
38227           forceEllipses: false
38228         })
38229
38230         .directive('uibPagination', ['$parse', 'uibPaginationConfig', function($parse, uibPaginationConfig) {
38231           return {
38232             scope: {
38233               totalItems: '=',
38234               firstText: '@',
38235               previousText: '@',
38236               nextText: '@',
38237               lastText: '@',
38238               ngDisabled:'='
38239             },
38240             require: ['uibPagination', '?ngModel'],
38241             controller: 'UibPaginationController',
38242             controllerAs: 'pagination',
38243             templateUrl: function(element, attrs) {
38244               return attrs.templateUrl || 'uib/template/pagination/pagination.html';
38245             },
38246             replace: true,
38247             link: function(scope, element, attrs, ctrls) {
38248               var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
38249
38250               if (!ngModelCtrl) {
38251                  return; // do nothing if no ng-model
38252               }
38253
38254               paginationCtrl.init(ngModelCtrl, uibPaginationConfig);
38255             }
38256           };
38257         }]);
38258
38259         /**
38260          * The following features are still outstanding: animation as a
38261          * function, placement as a function, inside, support for more triggers than
38262          * just mouse enter/leave, html tooltips, and selector delegation.
38263          */
38264         angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.stackedMap'])
38265
38266         /**
38267          * The $tooltip service creates tooltip- and popover-like directives as well as
38268          * houses global options for them.
38269          */
38270         .provider('$uibTooltip', function() {
38271           // The default options tooltip and popover.
38272           var defaultOptions = {
38273             placement: 'top',
38274             placementClassPrefix: '',
38275             animation: true,
38276             popupDelay: 0,
38277             popupCloseDelay: 0,
38278             useContentExp: false
38279           };
38280
38281           // Default hide triggers for each show trigger
38282           var triggerMap = {
38283             'mouseenter': 'mouseleave',
38284             'click': 'click',
38285             'outsideClick': 'outsideClick',
38286             'focus': 'blur',
38287             'none': ''
38288           };
38289
38290           // The options specified to the provider globally.
38291           var globalOptions = {};
38292
38293           /**
38294            * `options({})` allows global configuration of all tooltips in the
38295            * application.
38296            *
38297            *   var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
38298            *     // place tooltips left instead of top by default
38299            *     $tooltipProvider.options( { placement: 'left' } );
38300            *   });
38301            */
38302                 this.options = function(value) {
38303                         angular.extend(globalOptions, value);
38304                 };
38305
38306           /**
38307            * This allows you to extend the set of trigger mappings available. E.g.:
38308            *
38309            *   $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
38310            */
38311           this.setTriggers = function setTriggers(triggers) {
38312             angular.extend(triggerMap, triggers);
38313           };
38314
38315           /**
38316            * This is a helper function for translating camel-case to snake_case.
38317            */
38318           function snake_case(name) {
38319             var regexp = /[A-Z]/g;
38320             var separator = '-';
38321             return name.replace(regexp, function(letter, pos) {
38322               return (pos ? separator : '') + letter.toLowerCase();
38323             });
38324           }
38325
38326           /**
38327            * Returns the actual instance of the $tooltip service.
38328            * TODO support multiple triggers
38329            */
38330           this.$get = ['$window', '$compile', '$timeout', '$document', '$uibPosition', '$interpolate', '$rootScope', '$parse', '$$stackedMap', function($window, $compile, $timeout, $document, $position, $interpolate, $rootScope, $parse, $$stackedMap) {
38331             var openedTooltips = $$stackedMap.createNew();
38332             $document.on('keypress', keypressListener);
38333
38334             $rootScope.$on('$destroy', function() {
38335               $document.off('keypress', keypressListener);
38336             });
38337
38338             function keypressListener(e) {
38339               if (e.which === 27) {
38340                 var last = openedTooltips.top();
38341                 if (last) {
38342                   last.value.close();
38343                   openedTooltips.removeTop();
38344                   last = null;
38345                 }
38346               }
38347             }
38348
38349             return function $tooltip(ttType, prefix, defaultTriggerShow, options) {
38350               options = angular.extend({}, defaultOptions, globalOptions, options);
38351
38352               /**
38353                * Returns an object of show and hide triggers.
38354                *
38355                * If a trigger is supplied,
38356                * it is used to show the tooltip; otherwise, it will use the `trigger`
38357                * option passed to the `$tooltipProvider.options` method; else it will
38358                * default to the trigger supplied to this directive factory.
38359                *
38360                * The hide trigger is based on the show trigger. If the `trigger` option
38361                * was passed to the `$tooltipProvider.options` method, it will use the
38362                * mapped trigger from `triggerMap` or the passed trigger if the map is
38363                * undefined; otherwise, it uses the `triggerMap` value of the show
38364                * trigger; else it will just use the show trigger.
38365                */
38366               function getTriggers(trigger) {
38367                 var show = (trigger || options.trigger || defaultTriggerShow).split(' ');
38368                 var hide = show.map(function(trigger) {
38369                   return triggerMap[trigger] || trigger;
38370                 });
38371                 return {
38372                   show: show,
38373                   hide: hide
38374                 };
38375               }
38376
38377               var directiveName = snake_case(ttType);
38378
38379               var startSym = $interpolate.startSymbol();
38380               var endSym = $interpolate.endSymbol();
38381               var template =
38382                 '<div '+ directiveName + '-popup '+
38383                   'title="' + startSym + 'title' + endSym + '" '+
38384                   (options.useContentExp ?
38385                     'content-exp="contentExp()" ' :
38386                     'content="' + startSym + 'content' + endSym + '" ') +
38387                   'placement="' + startSym + 'placement' + endSym + '" '+
38388                   'popup-class="' + startSym + 'popupClass' + endSym + '" '+
38389                   'animation="animation" ' +
38390                   'is-open="isOpen"' +
38391                   'origin-scope="origScope" ' +
38392                   'style="visibility: hidden; display: block; top: -9999px; left: -9999px;"' +
38393                   '>' +
38394                 '</div>';
38395
38396               return {
38397                 compile: function(tElem, tAttrs) {
38398                   var tooltipLinker = $compile(template);
38399
38400                   return function link(scope, element, attrs, tooltipCtrl) {
38401                     var tooltip;
38402                     var tooltipLinkedScope;
38403                     var transitionTimeout;
38404                     var showTimeout;
38405                     var hideTimeout;
38406                     var positionTimeout;
38407                     var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
38408                     var triggers = getTriggers(undefined);
38409                     var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
38410                     var ttScope = scope.$new(true);
38411                     var repositionScheduled = false;
38412                     var isOpenParse = angular.isDefined(attrs[prefix + 'IsOpen']) ? $parse(attrs[prefix + 'IsOpen']) : false;
38413                     var contentParse = options.useContentExp ? $parse(attrs[ttType]) : false;
38414                     var observers = [];
38415
38416                     var positionTooltip = function() {
38417                       // check if tooltip exists and is not empty
38418                       if (!tooltip || !tooltip.html()) { return; }
38419
38420                       if (!positionTimeout) {
38421                         positionTimeout = $timeout(function() {
38422                           // Reset the positioning.
38423                           tooltip.css({ top: 0, left: 0 });
38424
38425                           // Now set the calculated positioning.
38426                           var ttPosition = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
38427                           tooltip.css({ top: ttPosition.top + 'px', left: ttPosition.left + 'px', visibility: 'visible' });
38428
38429                           // If the placement class is prefixed, still need
38430                           // to remove the TWBS standard class.
38431                           if (options.placementClassPrefix) {
38432                             tooltip.removeClass('top bottom left right');
38433                           }
38434
38435                           tooltip.removeClass(
38436                             options.placementClassPrefix + 'top ' +
38437                             options.placementClassPrefix + 'top-left ' +
38438                             options.placementClassPrefix + 'top-right ' +
38439                             options.placementClassPrefix + 'bottom ' +
38440                             options.placementClassPrefix + 'bottom-left ' +
38441                             options.placementClassPrefix + 'bottom-right ' +
38442                             options.placementClassPrefix + 'left ' +
38443                             options.placementClassPrefix + 'left-top ' +
38444                             options.placementClassPrefix + 'left-bottom ' +
38445                             options.placementClassPrefix + 'right ' +
38446                             options.placementClassPrefix + 'right-top ' +
38447                             options.placementClassPrefix + 'right-bottom');
38448
38449                           var placement = ttPosition.placement.split('-');
38450                           tooltip.addClass(placement[0], options.placementClassPrefix + ttPosition.placement);
38451                           $position.positionArrow(tooltip, ttPosition.placement);
38452
38453                           positionTimeout = null;
38454                         }, 0, false);
38455                       }
38456                     };
38457
38458                     // Set up the correct scope to allow transclusion later
38459                     ttScope.origScope = scope;
38460
38461                     // By default, the tooltip is not open.
38462                     // TODO add ability to start tooltip opened
38463                     ttScope.isOpen = false;
38464                     openedTooltips.add(ttScope, {
38465                       close: hide
38466                     });
38467
38468                     function toggleTooltipBind() {
38469                       if (!ttScope.isOpen) {
38470                         showTooltipBind();
38471                       } else {
38472                         hideTooltipBind();
38473                       }
38474                     }
38475
38476                     // Show the tooltip with delay if specified, otherwise show it immediately
38477                     function showTooltipBind() {
38478                       if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
38479                         return;
38480                       }
38481
38482                       cancelHide();
38483                       prepareTooltip();
38484
38485                       if (ttScope.popupDelay) {
38486                         // Do nothing if the tooltip was already scheduled to pop-up.
38487                         // This happens if show is triggered multiple times before any hide is triggered.
38488                         if (!showTimeout) {
38489                           showTimeout = $timeout(show, ttScope.popupDelay, false);
38490                         }
38491                       } else {
38492                         show();
38493                       }
38494                     }
38495
38496                     function hideTooltipBind() {
38497                       cancelShow();
38498
38499                       if (ttScope.popupCloseDelay) {
38500                         if (!hideTimeout) {
38501                           hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
38502                         }
38503                       } else {
38504                         hide();
38505                       }
38506                     }
38507
38508                     // Show the tooltip popup element.
38509                     function show() {
38510                       cancelShow();
38511                       cancelHide();
38512
38513                       // Don't show empty tooltips.
38514                       if (!ttScope.content) {
38515                         return angular.noop;
38516                       }
38517
38518                       createTooltip();
38519
38520                       // And show the tooltip.
38521                       ttScope.$evalAsync(function() {
38522                         ttScope.isOpen = true;
38523                         assignIsOpen(true);
38524                         positionTooltip();
38525                       });
38526                     }
38527
38528                     function cancelShow() {
38529                       if (showTimeout) {
38530                         $timeout.cancel(showTimeout);
38531                         showTimeout = null;
38532                       }
38533
38534                       if (positionTimeout) {
38535                         $timeout.cancel(positionTimeout);
38536                         positionTimeout = null;
38537                       }
38538                     }
38539
38540                     // Hide the tooltip popup element.
38541                     function hide() {
38542                       if (!ttScope) {
38543                         return;
38544                       }
38545
38546                       // First things first: we don't show it anymore.
38547                       ttScope.$evalAsync(function() {
38548                         ttScope.isOpen = false;
38549                         assignIsOpen(false);
38550                         // And now we remove it from the DOM. However, if we have animation, we
38551                         // need to wait for it to expire beforehand.
38552                         // FIXME: this is a placeholder for a port of the transitions library.
38553                         // The fade transition in TWBS is 150ms.
38554                         if (ttScope.animation) {
38555                           if (!transitionTimeout) {
38556                             transitionTimeout = $timeout(removeTooltip, 150, false);
38557                           }
38558                         } else {
38559                           removeTooltip();
38560                         }
38561                       });
38562                     }
38563
38564                     function cancelHide() {
38565                       if (hideTimeout) {
38566                         $timeout.cancel(hideTimeout);
38567                         hideTimeout = null;
38568                       }
38569                       if (transitionTimeout) {
38570                         $timeout.cancel(transitionTimeout);
38571                         transitionTimeout = null;
38572                       }
38573                     }
38574
38575                     function createTooltip() {
38576                       // There can only be one tooltip element per directive shown at once.
38577                       if (tooltip) {
38578                         return;
38579                       }
38580
38581                       tooltipLinkedScope = ttScope.$new();
38582                       tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) {
38583                         if (appendToBody) {
38584                           $document.find('body').append(tooltip);
38585                         } else {
38586                           element.after(tooltip);
38587                         }
38588                       });
38589
38590                       prepObservers();
38591                     }
38592
38593                     function removeTooltip() {
38594                       cancelShow();
38595                       cancelHide();
38596                       unregisterObservers();
38597
38598                       if (tooltip) {
38599                         tooltip.remove();
38600                         tooltip = null;
38601                       }
38602                       if (tooltipLinkedScope) {
38603                         tooltipLinkedScope.$destroy();
38604                         tooltipLinkedScope = null;
38605                       }
38606                     }
38607
38608                     /**
38609                      * Set the initial scope values. Once
38610                      * the tooltip is created, the observers
38611                      * will be added to keep things in sync.
38612                      */
38613                     function prepareTooltip() {
38614                       ttScope.title = attrs[prefix + 'Title'];
38615                       if (contentParse) {
38616                         ttScope.content = contentParse(scope);
38617                       } else {
38618                         ttScope.content = attrs[ttType];
38619                       }
38620
38621                       ttScope.popupClass = attrs[prefix + 'Class'];
38622                       ttScope.placement = angular.isDefined(attrs[prefix + 'Placement']) ? attrs[prefix + 'Placement'] : options.placement;
38623
38624                       var delay = parseInt(attrs[prefix + 'PopupDelay'], 10);
38625                       var closeDelay = parseInt(attrs[prefix + 'PopupCloseDelay'], 10);
38626                       ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay;
38627                       ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay;
38628                     }
38629
38630                     function assignIsOpen(isOpen) {
38631                       if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
38632                         isOpenParse.assign(scope, isOpen);
38633                       }
38634                     }
38635
38636                     ttScope.contentExp = function() {
38637                       return ttScope.content;
38638                     };
38639
38640                     /**
38641                      * Observe the relevant attributes.
38642                      */
38643                     attrs.$observe('disabled', function(val) {
38644                       if (val) {
38645                         cancelShow();
38646                       }
38647
38648                       if (val && ttScope.isOpen) {
38649                         hide();
38650                       }
38651                     });
38652
38653                     if (isOpenParse) {
38654                       scope.$watch(isOpenParse, function(val) {
38655                         if (ttScope && !val === ttScope.isOpen) {
38656                           toggleTooltipBind();
38657                         }
38658                       });
38659                     }
38660
38661                     function prepObservers() {
38662                       observers.length = 0;
38663
38664                       if (contentParse) {
38665                         observers.push(
38666                           scope.$watch(contentParse, function(val) {
38667                             ttScope.content = val;
38668                             if (!val && ttScope.isOpen) {
38669                               hide();
38670                             }
38671                           })
38672                         );
38673
38674                         observers.push(
38675                           tooltipLinkedScope.$watch(function() {
38676                             if (!repositionScheduled) {
38677                               repositionScheduled = true;
38678                               tooltipLinkedScope.$$postDigest(function() {
38679                                 repositionScheduled = false;
38680                                 if (ttScope && ttScope.isOpen) {
38681                                   positionTooltip();
38682                                 }
38683                               });
38684                             }
38685                           })
38686                         );
38687                       } else {
38688                         observers.push(
38689                           attrs.$observe(ttType, function(val) {
38690                             ttScope.content = val;
38691                             if (!val && ttScope.isOpen) {
38692                               hide();
38693                             } else {
38694                               positionTooltip();
38695                             }
38696                           })
38697                         );
38698                       }
38699
38700                       observers.push(
38701                         attrs.$observe(prefix + 'Title', function(val) {
38702                           ttScope.title = val;
38703                           if (ttScope.isOpen) {
38704                             positionTooltip();
38705                           }
38706                         })
38707                       );
38708
38709                       observers.push(
38710                         attrs.$observe(prefix + 'Placement', function(val) {
38711                           ttScope.placement = val ? val : options.placement;
38712                           if (ttScope.isOpen) {
38713                             positionTooltip();
38714                           }
38715                         })
38716                       );
38717                     }
38718
38719                     function unregisterObservers() {
38720                       if (observers.length) {
38721                         angular.forEach(observers, function(observer) {
38722                           observer();
38723                         });
38724                         observers.length = 0;
38725                       }
38726                     }
38727
38728                     // hide tooltips/popovers for outsideClick trigger
38729                     function bodyHideTooltipBind(e) {
38730                       if (!ttScope || !ttScope.isOpen || !tooltip) {
38731                         return;
38732                       }
38733                       // make sure the tooltip/popover link or tool tooltip/popover itself were not clicked
38734                       if (!element[0].contains(e.target) && !tooltip[0].contains(e.target)) {
38735                         hideTooltipBind();
38736                       }
38737                     }
38738
38739                     var unregisterTriggers = function() {
38740                       triggers.show.forEach(function(trigger) {
38741                         if (trigger === 'outsideClick') {
38742                           element.off('click', toggleTooltipBind);
38743                         } else {
38744                           element.off(trigger, showTooltipBind);
38745                           element.off(trigger, toggleTooltipBind);
38746                         }
38747                       });
38748                       triggers.hide.forEach(function(trigger) {
38749                         if (trigger === 'outsideClick') {
38750                           $document.off('click', bodyHideTooltipBind);
38751                         } else {
38752                           element.off(trigger, hideTooltipBind);
38753                         }
38754                       });
38755                     };
38756
38757                     function prepTriggers() {
38758                       var val = attrs[prefix + 'Trigger'];
38759                       unregisterTriggers();
38760
38761                       triggers = getTriggers(val);
38762
38763                       if (triggers.show !== 'none') {
38764                         triggers.show.forEach(function(trigger, idx) {
38765                           if (trigger === 'outsideClick') {
38766                             element.on('click', toggleTooltipBind);
38767                             $document.on('click', bodyHideTooltipBind);
38768                           } else if (trigger === triggers.hide[idx]) {
38769                             element.on(trigger, toggleTooltipBind);
38770                           } else if (trigger) {
38771                             element.on(trigger, showTooltipBind);
38772                             element.on(triggers.hide[idx], hideTooltipBind);
38773                           }
38774
38775                           element.on('keypress', function(e) {
38776                             if (e.which === 27) {
38777                               hideTooltipBind();
38778                             }
38779                           });
38780                         });
38781                       }
38782                     }
38783
38784                     prepTriggers();
38785
38786                     var animation = scope.$eval(attrs[prefix + 'Animation']);
38787                     ttScope.animation = angular.isDefined(animation) ? !!animation : options.animation;
38788
38789                     var appendToBodyVal;
38790                     var appendKey = prefix + 'AppendToBody';
38791                     if (appendKey in attrs && attrs[appendKey] === undefined) {
38792                       appendToBodyVal = true;
38793                     } else {
38794                       appendToBodyVal = scope.$eval(attrs[appendKey]);
38795                     }
38796
38797                     appendToBody = angular.isDefined(appendToBodyVal) ? appendToBodyVal : appendToBody;
38798
38799                     // if a tooltip is attached to <body> we need to remove it on
38800                     // location change as its parent scope will probably not be destroyed
38801                     // by the change.
38802                     if (appendToBody) {
38803                       scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess() {
38804                         if (ttScope.isOpen) {
38805                           hide();
38806                         }
38807                       });
38808                     }
38809
38810                     // Make sure tooltip is destroyed and removed.
38811                     scope.$on('$destroy', function onDestroyTooltip() {
38812                       unregisterTriggers();
38813                       removeTooltip();
38814                       openedTooltips.remove(ttScope);
38815                       ttScope = null;
38816                     });
38817                   };
38818                 }
38819               };
38820             };
38821           }];
38822         })
38823
38824         // This is mostly ngInclude code but with a custom scope
38825         .directive('uibTooltipTemplateTransclude', [
38826                  '$animate', '$sce', '$compile', '$templateRequest',
38827         function ($animate, $sce, $compile, $templateRequest) {
38828           return {
38829             link: function(scope, elem, attrs) {
38830               var origScope = scope.$eval(attrs.tooltipTemplateTranscludeScope);
38831
38832               var changeCounter = 0,
38833                 currentScope,
38834                 previousElement,
38835                 currentElement;
38836
38837               var cleanupLastIncludeContent = function() {
38838                 if (previousElement) {
38839                   previousElement.remove();
38840                   previousElement = null;
38841                 }
38842
38843                 if (currentScope) {
38844                   currentScope.$destroy();
38845                   currentScope = null;
38846                 }
38847
38848                 if (currentElement) {
38849                   $animate.leave(currentElement).then(function() {
38850                     previousElement = null;
38851                   });
38852                   previousElement = currentElement;
38853                   currentElement = null;
38854                 }
38855               };
38856
38857               scope.$watch($sce.parseAsResourceUrl(attrs.uibTooltipTemplateTransclude), function(src) {
38858                 var thisChangeId = ++changeCounter;
38859
38860                 if (src) {
38861                   //set the 2nd param to true to ignore the template request error so that the inner
38862                   //contents and scope can be cleaned up.
38863                   $templateRequest(src, true).then(function(response) {
38864                     if (thisChangeId !== changeCounter) { return; }
38865                     var newScope = origScope.$new();
38866                     var template = response;
38867
38868                     var clone = $compile(template)(newScope, function(clone) {
38869                       cleanupLastIncludeContent();
38870                       $animate.enter(clone, elem);
38871                     });
38872
38873                     currentScope = newScope;
38874                     currentElement = clone;
38875
38876                     currentScope.$emit('$includeContentLoaded', src);
38877                   }, function() {
38878                     if (thisChangeId === changeCounter) {
38879                       cleanupLastIncludeContent();
38880                       scope.$emit('$includeContentError', src);
38881                     }
38882                   });
38883                   scope.$emit('$includeContentRequested', src);
38884                 } else {
38885                   cleanupLastIncludeContent();
38886                 }
38887               });
38888
38889               scope.$on('$destroy', cleanupLastIncludeContent);
38890             }
38891           };
38892         }])
38893
38894         /**
38895          * Note that it's intentional that these classes are *not* applied through $animate.
38896          * They must not be animated as they're expected to be present on the tooltip on
38897          * initialization.
38898          */
38899         .directive('uibTooltipClasses', ['$uibPosition', function($uibPosition) {
38900           return {
38901             restrict: 'A',
38902             link: function(scope, element, attrs) {
38903               // need to set the primary position so the
38904               // arrow has space during position measure.
38905               // tooltip.positionTooltip()
38906               if (scope.placement) {
38907                 // // There are no top-left etc... classes
38908                 // // in TWBS, so we need the primary position.
38909                 var position = $uibPosition.parsePlacement(scope.placement);
38910                 element.addClass(position[0]);
38911               } else {
38912                 element.addClass('top');
38913               }
38914
38915               if (scope.popupClass) {
38916                 element.addClass(scope.popupClass);
38917               }
38918
38919               if (scope.animation()) {
38920                 element.addClass(attrs.tooltipAnimationClass);
38921               }
38922             }
38923           };
38924         }])
38925
38926         .directive('uibTooltipPopup', function() {
38927           return {
38928             replace: true,
38929             scope: { content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
38930             templateUrl: 'uib/template/tooltip/tooltip-popup.html'
38931           };
38932         })
38933
38934         .directive('uibTooltip', [ '$uibTooltip', function($uibTooltip) {
38935           return $uibTooltip('uibTooltip', 'tooltip', 'mouseenter');
38936         }])
38937
38938         .directive('uibTooltipTemplatePopup', function() {
38939           return {
38940             replace: true,
38941             scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&',
38942               originScope: '&' },
38943             templateUrl: 'uib/template/tooltip/tooltip-template-popup.html'
38944           };
38945         })
38946
38947         .directive('uibTooltipTemplate', ['$uibTooltip', function($uibTooltip) {
38948           return $uibTooltip('uibTooltipTemplate', 'tooltip', 'mouseenter', {
38949             useContentExp: true
38950           });
38951         }])
38952
38953         .directive('uibTooltipHtmlPopup', function() {
38954           return {
38955             replace: true,
38956             scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
38957             templateUrl: 'uib/template/tooltip/tooltip-html-popup.html'
38958           };
38959         })
38960
38961         .directive('uibTooltipHtml', ['$uibTooltip', function($uibTooltip) {
38962           return $uibTooltip('uibTooltipHtml', 'tooltip', 'mouseenter', {
38963             useContentExp: true
38964           });
38965         }]);
38966
38967         /**
38968          * The following features are still outstanding: popup delay, animation as a
38969          * function, placement as a function, inside, support for more triggers than
38970          * just mouse enter/leave, and selector delegatation.
38971          */
38972         angular.module('ui.bootstrap.popover', ['ui.bootstrap.tooltip'])
38973
38974         .directive('uibPopoverTemplatePopup', function() {
38975           return {
38976             replace: true,
38977             scope: { title: '@', contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&',
38978               originScope: '&' },
38979             templateUrl: 'uib/template/popover/popover-template.html'
38980           };
38981         })
38982
38983         .directive('uibPopoverTemplate', ['$uibTooltip', function($uibTooltip) {
38984           return $uibTooltip('uibPopoverTemplate', 'popover', 'click', {
38985             useContentExp: true
38986           });
38987         }])
38988
38989         .directive('uibPopoverHtmlPopup', function() {
38990           return {
38991             replace: true,
38992             scope: { contentExp: '&', title: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
38993             templateUrl: 'uib/template/popover/popover-html.html'
38994           };
38995         })
38996
38997         .directive('uibPopoverHtml', ['$uibTooltip', function($uibTooltip) {
38998           return $uibTooltip('uibPopoverHtml', 'popover', 'click', {
38999             useContentExp: true
39000           });
39001         }])
39002
39003         .directive('uibPopoverPopup', function() {
39004           return {
39005             replace: true,
39006             scope: { title: '@', content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
39007             templateUrl: 'uib/template/popover/popover.html'
39008           };
39009         })
39010
39011         .directive('uibPopover', ['$uibTooltip', function($uibTooltip) {
39012           return $uibTooltip('uibPopover', 'popover', 'click');
39013         }]);
39014
39015         angular.module('ui.bootstrap.progressbar', [])
39016
39017         .constant('uibProgressConfig', {
39018           animate: true,
39019           max: 100
39020         })
39021
39022         .controller('UibProgressController', ['$scope', '$attrs', 'uibProgressConfig', function($scope, $attrs, progressConfig) {
39023           var self = this,
39024               animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
39025
39026           this.bars = [];
39027           $scope.max = angular.isDefined($scope.max) ? $scope.max : progressConfig.max;
39028
39029           this.addBar = function(bar, element, attrs) {
39030             if (!animate) {
39031               element.css({'transition': 'none'});
39032             }
39033
39034             this.bars.push(bar);
39035
39036             bar.max = $scope.max;
39037             bar.title = attrs && angular.isDefined(attrs.title) ? attrs.title : 'progressbar';
39038
39039             bar.$watch('value', function(value) {
39040               bar.recalculatePercentage();
39041             });
39042
39043             bar.recalculatePercentage = function() {
39044               var totalPercentage = self.bars.reduce(function(total, bar) {
39045                 bar.percent = +(100 * bar.value / bar.max).toFixed(2);
39046                 return total + bar.percent;
39047               }, 0);
39048
39049               if (totalPercentage > 100) {
39050                 bar.percent -= totalPercentage - 100;
39051               }
39052             };
39053
39054             bar.$on('$destroy', function() {
39055               element = null;
39056               self.removeBar(bar);
39057             });
39058           };
39059
39060           this.removeBar = function(bar) {
39061             this.bars.splice(this.bars.indexOf(bar), 1);
39062             this.bars.forEach(function (bar) {
39063               bar.recalculatePercentage();
39064             });
39065           };
39066
39067           $scope.$watch('max', function(max) {
39068             self.bars.forEach(function(bar) {
39069               bar.max = $scope.max;
39070               bar.recalculatePercentage();
39071             });
39072           });
39073         }])
39074
39075         .directive('uibProgress', function() {
39076           return {
39077             replace: true,
39078             transclude: true,
39079             controller: 'UibProgressController',
39080             require: 'uibProgress',
39081             scope: {
39082               max: '=?'
39083             },
39084             templateUrl: 'uib/template/progressbar/progress.html'
39085           };
39086         })
39087
39088         .directive('uibBar', function() {
39089           return {
39090             replace: true,
39091             transclude: true,
39092             require: '^uibProgress',
39093             scope: {
39094               value: '=',
39095               type: '@'
39096             },
39097             templateUrl: 'uib/template/progressbar/bar.html',
39098             link: function(scope, element, attrs, progressCtrl) {
39099               progressCtrl.addBar(scope, element, attrs);
39100             }
39101           };
39102         })
39103
39104         .directive('uibProgressbar', function() {
39105           return {
39106             replace: true,
39107             transclude: true,
39108             controller: 'UibProgressController',
39109             scope: {
39110               value: '=',
39111               max: '=?',
39112               type: '@'
39113             },
39114             templateUrl: 'uib/template/progressbar/progressbar.html',
39115             link: function(scope, element, attrs, progressCtrl) {
39116               progressCtrl.addBar(scope, angular.element(element.children()[0]), {title: attrs.title});
39117             }
39118           };
39119         });
39120
39121         angular.module('ui.bootstrap.rating', [])
39122
39123         .constant('uibRatingConfig', {
39124           max: 5,
39125           stateOn: null,
39126           stateOff: null,
39127           titles : ['one', 'two', 'three', 'four', 'five']
39128         })
39129
39130         .controller('UibRatingController', ['$scope', '$attrs', 'uibRatingConfig', function($scope, $attrs, ratingConfig) {
39131           var ngModelCtrl = { $setViewValue: angular.noop };
39132
39133           this.init = function(ngModelCtrl_) {
39134             ngModelCtrl = ngModelCtrl_;
39135             ngModelCtrl.$render = this.render;
39136
39137             ngModelCtrl.$formatters.push(function(value) {
39138               if (angular.isNumber(value) && value << 0 !== value) {
39139                 value = Math.round(value);
39140               }
39141
39142               return value;
39143             });
39144
39145             this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
39146             this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
39147             var tmpTitles = angular.isDefined($attrs.titles) ? $scope.$parent.$eval($attrs.titles) : ratingConfig.titles ;
39148             this.titles = angular.isArray(tmpTitles) && tmpTitles.length > 0 ?
39149               tmpTitles : ratingConfig.titles;
39150
39151             var ratingStates = angular.isDefined($attrs.ratingStates) ?
39152               $scope.$parent.$eval($attrs.ratingStates) :
39153               new Array(angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max);
39154             $scope.range = this.buildTemplateObjects(ratingStates);
39155           };
39156
39157           this.buildTemplateObjects = function(states) {
39158             for (var i = 0, n = states.length; i < n; i++) {
39159               states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff, title: this.getTitle(i) }, states[i]);
39160             }
39161             return states;
39162           };
39163
39164           this.getTitle = function(index) {
39165             if (index >= this.titles.length) {
39166               return index + 1;
39167             }
39168
39169             return this.titles[index];
39170           };
39171
39172           $scope.rate = function(value) {
39173             if (!$scope.readonly && value >= 0 && value <= $scope.range.length) {
39174               ngModelCtrl.$setViewValue(ngModelCtrl.$viewValue === value ? 0 : value);
39175               ngModelCtrl.$render();
39176             }
39177           };
39178
39179           $scope.enter = function(value) {
39180             if (!$scope.readonly) {
39181               $scope.value = value;
39182             }
39183             $scope.onHover({value: value});
39184           };
39185
39186           $scope.reset = function() {
39187             $scope.value = ngModelCtrl.$viewValue;
39188             $scope.onLeave();
39189           };
39190
39191           $scope.onKeydown = function(evt) {
39192             if (/(37|38|39|40)/.test(evt.which)) {
39193               evt.preventDefault();
39194               evt.stopPropagation();
39195               $scope.rate($scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1));
39196             }
39197           };
39198
39199           this.render = function() {
39200             $scope.value = ngModelCtrl.$viewValue;
39201           };
39202         }])
39203
39204         .directive('uibRating', function() {
39205           return {
39206             require: ['uibRating', 'ngModel'],
39207             scope: {
39208               readonly: '=?',
39209               onHover: '&',
39210               onLeave: '&'
39211             },
39212             controller: 'UibRatingController',
39213             templateUrl: 'uib/template/rating/rating.html',
39214             replace: true,
39215             link: function(scope, element, attrs, ctrls) {
39216               var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1];
39217               ratingCtrl.init(ngModelCtrl);
39218             }
39219           };
39220         });
39221
39222         angular.module('ui.bootstrap.tabs', [])
39223
39224         .controller('UibTabsetController', ['$scope', function ($scope) {
39225           var ctrl = this,
39226               tabs = ctrl.tabs = $scope.tabs = [];
39227
39228           ctrl.select = function(selectedTab) {
39229             angular.forEach(tabs, function(tab) {
39230               if (tab.active && tab !== selectedTab) {
39231                 tab.active = false;
39232                 tab.onDeselect();
39233                 selectedTab.selectCalled = false;
39234               }
39235             });
39236             selectedTab.active = true;
39237             // only call select if it has not already been called
39238             if (!selectedTab.selectCalled) {
39239               selectedTab.onSelect();
39240               selectedTab.selectCalled = true;
39241             }
39242           };
39243
39244           ctrl.addTab = function addTab(tab) {
39245             tabs.push(tab);
39246             // we can't run the select function on the first tab
39247             // since that would select it twice
39248             if (tabs.length === 1 && tab.active !== false) {
39249               tab.active = true;
39250             } else if (tab.active) {
39251               ctrl.select(tab);
39252             } else {
39253               tab.active = false;
39254             }
39255           };
39256
39257           ctrl.removeTab = function removeTab(tab) {
39258             var index = tabs.indexOf(tab);
39259             //Select a new tab if the tab to be removed is selected and not destroyed
39260             if (tab.active && tabs.length > 1 && !destroyed) {
39261               //If this is the last tab, select the previous tab. else, the next tab.
39262               var newActiveIndex = index === tabs.length - 1 ? index - 1 : index + 1;
39263               ctrl.select(tabs[newActiveIndex]);
39264             }
39265             tabs.splice(index, 1);
39266           };
39267
39268           var destroyed;
39269           $scope.$on('$destroy', function() {
39270             destroyed = true;
39271           });
39272         }])
39273
39274         .directive('uibTabset', function() {
39275           return {
39276             transclude: true,
39277             replace: true,
39278             scope: {
39279               type: '@'
39280             },
39281             controller: 'UibTabsetController',
39282             templateUrl: 'uib/template/tabs/tabset.html',
39283             link: function(scope, element, attrs) {
39284               scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
39285               scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
39286             }
39287           };
39288         })
39289
39290         .directive('uibTab', ['$parse', function($parse) {
39291           return {
39292             require: '^uibTabset',
39293             replace: true,
39294             templateUrl: 'uib/template/tabs/tab.html',
39295             transclude: true,
39296             scope: {
39297               active: '=?',
39298               heading: '@',
39299               onSelect: '&select', //This callback is called in contentHeadingTransclude
39300                                   //once it inserts the tab's content into the dom
39301               onDeselect: '&deselect'
39302             },
39303             controller: function() {
39304               //Empty controller so other directives can require being 'under' a tab
39305             },
39306             controllerAs: 'tab',
39307             link: function(scope, elm, attrs, tabsetCtrl, transclude) {
39308               scope.$watch('active', function(active) {
39309                 if (active) {
39310                   tabsetCtrl.select(scope);
39311                 }
39312               });
39313
39314               scope.disabled = false;
39315               if (attrs.disable) {
39316                 scope.$parent.$watch($parse(attrs.disable), function(value) {
39317                   scope.disabled = !! value;
39318                 });
39319               }
39320
39321               scope.select = function() {
39322                 if (!scope.disabled) {
39323                   scope.active = true;
39324                 }
39325               };
39326
39327               tabsetCtrl.addTab(scope);
39328               scope.$on('$destroy', function() {
39329                 tabsetCtrl.removeTab(scope);
39330               });
39331
39332               //We need to transclude later, once the content container is ready.
39333               //when this link happens, we're inside a tab heading.
39334               scope.$transcludeFn = transclude;
39335             }
39336           };
39337         }])
39338
39339         .directive('uibTabHeadingTransclude', function() {
39340           return {
39341             restrict: 'A',
39342             require: '^uibTab',
39343             link: function(scope, elm) {
39344               scope.$watch('headingElement', function updateHeadingElement(heading) {
39345                 if (heading) {
39346                   elm.html('');
39347                   elm.append(heading);
39348                 }
39349               });
39350             }
39351           };
39352         })
39353
39354         .directive('uibTabContentTransclude', function() {
39355           return {
39356             restrict: 'A',
39357             require: '^uibTabset',
39358             link: function(scope, elm, attrs) {
39359               var tab = scope.$eval(attrs.uibTabContentTransclude);
39360
39361               //Now our tab is ready to be transcluded: both the tab heading area
39362               //and the tab content area are loaded.  Transclude 'em both.
39363               tab.$transcludeFn(tab.$parent, function(contents) {
39364                 angular.forEach(contents, function(node) {
39365                   if (isTabHeading(node)) {
39366                     //Let tabHeadingTransclude know.
39367                     tab.headingElement = node;
39368                   } else {
39369                     elm.append(node);
39370                   }
39371                 });
39372               });
39373             }
39374           };
39375
39376           function isTabHeading(node) {
39377             return node.tagName && (
39378               node.hasAttribute('uib-tab-heading') ||
39379               node.hasAttribute('data-uib-tab-heading') ||
39380               node.hasAttribute('x-uib-tab-heading') ||
39381               node.tagName.toLowerCase() === 'uib-tab-heading' ||
39382               node.tagName.toLowerCase() === 'data-uib-tab-heading' ||
39383               node.tagName.toLowerCase() === 'x-uib-tab-heading'
39384             );
39385           }
39386         });
39387
39388         angular.module('ui.bootstrap.timepicker', [])
39389
39390         .constant('uibTimepickerConfig', {
39391           hourStep: 1,
39392           minuteStep: 1,
39393           secondStep: 1,
39394           showMeridian: true,
39395           showSeconds: false,
39396           meridians: null,
39397           readonlyInput: false,
39398           mousewheel: true,
39399           arrowkeys: true,
39400           showSpinners: true
39401         })
39402
39403         .controller('UibTimepickerController', ['$scope', '$element', '$attrs', '$parse', '$log', '$locale', 'uibTimepickerConfig', function($scope, $element, $attrs, $parse, $log, $locale, timepickerConfig) {
39404           var selected = new Date(),
39405               ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
39406               meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS;
39407
39408           $scope.tabindex = angular.isDefined($attrs.tabindex) ? $attrs.tabindex : 0;
39409           $element.removeAttr('tabindex');
39410
39411           this.init = function(ngModelCtrl_, inputs) {
39412             ngModelCtrl = ngModelCtrl_;
39413             ngModelCtrl.$render = this.render;
39414
39415             ngModelCtrl.$formatters.unshift(function(modelValue) {
39416               return modelValue ? new Date(modelValue) : null;
39417             });
39418
39419             var hoursInputEl = inputs.eq(0),
39420                 minutesInputEl = inputs.eq(1),
39421                 secondsInputEl = inputs.eq(2);
39422
39423             var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel;
39424
39425             if (mousewheel) {
39426               this.setupMousewheelEvents(hoursInputEl, minutesInputEl, secondsInputEl);
39427             }
39428
39429             var arrowkeys = angular.isDefined($attrs.arrowkeys) ? $scope.$parent.$eval($attrs.arrowkeys) : timepickerConfig.arrowkeys;
39430             if (arrowkeys) {
39431               this.setupArrowkeyEvents(hoursInputEl, minutesInputEl, secondsInputEl);
39432             }
39433
39434             $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput;
39435             this.setupInputEvents(hoursInputEl, minutesInputEl, secondsInputEl);
39436           };
39437
39438           var hourStep = timepickerConfig.hourStep;
39439           if ($attrs.hourStep) {
39440             $scope.$parent.$watch($parse($attrs.hourStep), function(value) {
39441               hourStep = parseInt(value, 10);
39442             });
39443           }
39444
39445           var minuteStep = timepickerConfig.minuteStep;
39446           if ($attrs.minuteStep) {
39447             $scope.$parent.$watch($parse($attrs.minuteStep), function(value) {
39448               minuteStep = parseInt(value, 10);
39449             });
39450           }
39451
39452           var min;
39453           $scope.$parent.$watch($parse($attrs.min), function(value) {
39454             var dt = new Date(value);
39455             min = isNaN(dt) ? undefined : dt;
39456           });
39457
39458           var max;
39459           $scope.$parent.$watch($parse($attrs.max), function(value) {
39460             var dt = new Date(value);
39461             max = isNaN(dt) ? undefined : dt;
39462           });
39463
39464           var disabled = false;
39465           if ($attrs.ngDisabled) {
39466             $scope.$parent.$watch($parse($attrs.ngDisabled), function(value) {
39467               disabled = value;
39468             });
39469           }
39470
39471           $scope.noIncrementHours = function() {
39472             var incrementedSelected = addMinutes(selected, hourStep * 60);
39473             return disabled || incrementedSelected > max ||
39474               incrementedSelected < selected && incrementedSelected < min;
39475           };
39476
39477           $scope.noDecrementHours = function() {
39478             var decrementedSelected = addMinutes(selected, -hourStep * 60);
39479             return disabled || decrementedSelected < min ||
39480               decrementedSelected > selected && decrementedSelected > max;
39481           };
39482
39483           $scope.noIncrementMinutes = function() {
39484             var incrementedSelected = addMinutes(selected, minuteStep);
39485             return disabled || incrementedSelected > max ||
39486               incrementedSelected < selected && incrementedSelected < min;
39487           };
39488
39489           $scope.noDecrementMinutes = function() {
39490             var decrementedSelected = addMinutes(selected, -minuteStep);
39491             return disabled || decrementedSelected < min ||
39492               decrementedSelected > selected && decrementedSelected > max;
39493           };
39494
39495           $scope.noIncrementSeconds = function() {
39496             var incrementedSelected = addSeconds(selected, secondStep);
39497             return disabled || incrementedSelected > max ||
39498               incrementedSelected < selected && incrementedSelected < min;
39499           };
39500
39501           $scope.noDecrementSeconds = function() {
39502             var decrementedSelected = addSeconds(selected, -secondStep);
39503             return disabled || decrementedSelected < min ||
39504               decrementedSelected > selected && decrementedSelected > max;
39505           };
39506
39507           $scope.noToggleMeridian = function() {
39508             if (selected.getHours() < 12) {
39509               return disabled || addMinutes(selected, 12 * 60) > max;
39510             }
39511
39512             return disabled || addMinutes(selected, -12 * 60) < min;
39513           };
39514
39515           var secondStep = timepickerConfig.secondStep;
39516           if ($attrs.secondStep) {
39517             $scope.$parent.$watch($parse($attrs.secondStep), function(value) {
39518               secondStep = parseInt(value, 10);
39519             });
39520           }
39521
39522           $scope.showSeconds = timepickerConfig.showSeconds;
39523           if ($attrs.showSeconds) {
39524             $scope.$parent.$watch($parse($attrs.showSeconds), function(value) {
39525               $scope.showSeconds = !!value;
39526             });
39527           }
39528
39529           // 12H / 24H mode
39530           $scope.showMeridian = timepickerConfig.showMeridian;
39531           if ($attrs.showMeridian) {
39532             $scope.$parent.$watch($parse($attrs.showMeridian), function(value) {
39533               $scope.showMeridian = !!value;
39534
39535               if (ngModelCtrl.$error.time) {
39536                 // Evaluate from template
39537                 var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
39538                 if (angular.isDefined(hours) && angular.isDefined(minutes)) {
39539                   selected.setHours(hours);
39540                   refresh();
39541                 }
39542               } else {
39543                 updateTemplate();
39544               }
39545             });
39546           }
39547
39548           // Get $scope.hours in 24H mode if valid
39549           function getHoursFromTemplate() {
39550             var hours = parseInt($scope.hours, 10);
39551             var valid = $scope.showMeridian ? hours > 0 && hours < 13 :
39552               hours >= 0 && hours < 24;
39553             if (!valid) {
39554               return undefined;
39555             }
39556
39557             if ($scope.showMeridian) {
39558               if (hours === 12) {
39559                 hours = 0;
39560               }
39561               if ($scope.meridian === meridians[1]) {
39562                 hours = hours + 12;
39563               }
39564             }
39565             return hours;
39566           }
39567
39568           function getMinutesFromTemplate() {
39569             var minutes = parseInt($scope.minutes, 10);
39570             return minutes >= 0 && minutes < 60 ? minutes : undefined;
39571           }
39572
39573           function getSecondsFromTemplate() {
39574             var seconds = parseInt($scope.seconds, 10);
39575             return seconds >= 0 && seconds < 60 ? seconds : undefined;
39576           }
39577
39578           function pad(value) {
39579             if (value === null) {
39580               return '';
39581             }
39582
39583             return angular.isDefined(value) && value.toString().length < 2 ?
39584               '0' + value : value.toString();
39585           }
39586
39587           // Respond on mousewheel spin
39588           this.setupMousewheelEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
39589             var isScrollingUp = function(e) {
39590               if (e.originalEvent) {
39591                 e = e.originalEvent;
39592               }
39593               //pick correct delta variable depending on event
39594               var delta = e.wheelDelta ? e.wheelDelta : -e.deltaY;
39595               return e.detail || delta > 0;
39596             };
39597
39598             hoursInputEl.bind('mousewheel wheel', function(e) {
39599               if (!disabled) {
39600                 $scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours());
39601               }
39602               e.preventDefault();
39603             });
39604
39605             minutesInputEl.bind('mousewheel wheel', function(e) {
39606               if (!disabled) {
39607                 $scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes());
39608               }
39609               e.preventDefault();
39610             });
39611
39612              secondsInputEl.bind('mousewheel wheel', function(e) {
39613               if (!disabled) {
39614                 $scope.$apply(isScrollingUp(e) ? $scope.incrementSeconds() : $scope.decrementSeconds());
39615               }
39616               e.preventDefault();
39617             });
39618           };
39619
39620           // Respond on up/down arrowkeys
39621           this.setupArrowkeyEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
39622             hoursInputEl.bind('keydown', function(e) {
39623               if (!disabled) {
39624                 if (e.which === 38) { // up
39625                   e.preventDefault();
39626                   $scope.incrementHours();
39627                   $scope.$apply();
39628                 } else if (e.which === 40) { // down
39629                   e.preventDefault();
39630                   $scope.decrementHours();
39631                   $scope.$apply();
39632                 }
39633               }
39634             });
39635
39636             minutesInputEl.bind('keydown', function(e) {
39637               if (!disabled) {
39638                 if (e.which === 38) { // up
39639                   e.preventDefault();
39640                   $scope.incrementMinutes();
39641                   $scope.$apply();
39642                 } else if (e.which === 40) { // down
39643                   e.preventDefault();
39644                   $scope.decrementMinutes();
39645                   $scope.$apply();
39646                 }
39647               }
39648             });
39649
39650             secondsInputEl.bind('keydown', function(e) {
39651               if (!disabled) {
39652                 if (e.which === 38) { // up
39653                   e.preventDefault();
39654                   $scope.incrementSeconds();
39655                   $scope.$apply();
39656                 } else if (e.which === 40) { // down
39657                   e.preventDefault();
39658                   $scope.decrementSeconds();
39659                   $scope.$apply();
39660                 }
39661               }
39662             });
39663           };
39664
39665           this.setupInputEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
39666             if ($scope.readonlyInput) {
39667               $scope.updateHours = angular.noop;
39668               $scope.updateMinutes = angular.noop;
39669               $scope.updateSeconds = angular.noop;
39670               return;
39671             }
39672
39673             var invalidate = function(invalidHours, invalidMinutes, invalidSeconds) {
39674               ngModelCtrl.$setViewValue(null);
39675               ngModelCtrl.$setValidity('time', false);
39676               if (angular.isDefined(invalidHours)) {
39677                 $scope.invalidHours = invalidHours;
39678               }
39679
39680               if (angular.isDefined(invalidMinutes)) {
39681                 $scope.invalidMinutes = invalidMinutes;
39682               }
39683
39684               if (angular.isDefined(invalidSeconds)) {
39685                 $scope.invalidSeconds = invalidSeconds;
39686               }
39687             };
39688
39689             $scope.updateHours = function() {
39690               var hours = getHoursFromTemplate(),
39691                 minutes = getMinutesFromTemplate();
39692
39693               ngModelCtrl.$setDirty();
39694
39695               if (angular.isDefined(hours) && angular.isDefined(minutes)) {
39696                 selected.setHours(hours);
39697                 selected.setMinutes(minutes);
39698                 if (selected < min || selected > max) {
39699                   invalidate(true);
39700                 } else {
39701                   refresh('h');
39702                 }
39703               } else {
39704                 invalidate(true);
39705               }
39706             };
39707
39708             hoursInputEl.bind('blur', function(e) {
39709               ngModelCtrl.$setTouched();
39710               if ($scope.hours === null || $scope.hours === '') {
39711                 invalidate(true);
39712               } else if (!$scope.invalidHours && $scope.hours < 10) {
39713                 $scope.$apply(function() {
39714                   $scope.hours = pad($scope.hours);
39715                 });
39716               }
39717             });
39718
39719             $scope.updateMinutes = function() {
39720               var minutes = getMinutesFromTemplate(),
39721                 hours = getHoursFromTemplate();
39722
39723               ngModelCtrl.$setDirty();
39724
39725               if (angular.isDefined(minutes) && angular.isDefined(hours)) {
39726                 selected.setHours(hours);
39727                 selected.setMinutes(minutes);
39728                 if (selected < min || selected > max) {
39729                   invalidate(undefined, true);
39730                 } else {
39731                   refresh('m');
39732                 }
39733               } else {
39734                 invalidate(undefined, true);
39735               }
39736             };
39737
39738             minutesInputEl.bind('blur', function(e) {
39739               ngModelCtrl.$setTouched();
39740               if ($scope.minutes === null) {
39741                 invalidate(undefined, true);
39742               } else if (!$scope.invalidMinutes && $scope.minutes < 10) {
39743                 $scope.$apply(function() {
39744                   $scope.minutes = pad($scope.minutes);
39745                 });
39746               }
39747             });
39748
39749             $scope.updateSeconds = function() {
39750               var seconds = getSecondsFromTemplate();
39751
39752               ngModelCtrl.$setDirty();
39753
39754               if (angular.isDefined(seconds)) {
39755                 selected.setSeconds(seconds);
39756                 refresh('s');
39757               } else {
39758                 invalidate(undefined, undefined, true);
39759               }
39760             };
39761
39762             secondsInputEl.bind('blur', function(e) {
39763               if (!$scope.invalidSeconds && $scope.seconds < 10) {
39764                 $scope.$apply( function() {
39765                   $scope.seconds = pad($scope.seconds);
39766                 });
39767               }
39768             });
39769
39770           };
39771
39772           this.render = function() {
39773             var date = ngModelCtrl.$viewValue;
39774
39775             if (isNaN(date)) {
39776               ngModelCtrl.$setValidity('time', false);
39777               $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
39778             } else {
39779               if (date) {
39780                 selected = date;
39781               }
39782
39783               if (selected < min || selected > max) {
39784                 ngModelCtrl.$setValidity('time', false);
39785                 $scope.invalidHours = true;
39786                 $scope.invalidMinutes = true;
39787               } else {
39788                 makeValid();
39789               }
39790               updateTemplate();
39791             }
39792           };
39793
39794           // Call internally when we know that model is valid.
39795           function refresh(keyboardChange) {
39796             makeValid();
39797             ngModelCtrl.$setViewValue(new Date(selected));
39798             updateTemplate(keyboardChange);
39799           }
39800
39801           function makeValid() {
39802             ngModelCtrl.$setValidity('time', true);
39803             $scope.invalidHours = false;
39804             $scope.invalidMinutes = false;
39805             $scope.invalidSeconds = false;
39806           }
39807
39808           function updateTemplate(keyboardChange) {
39809             if (!ngModelCtrl.$modelValue) {
39810               $scope.hours = null;
39811               $scope.minutes = null;
39812               $scope.seconds = null;
39813               $scope.meridian = meridians[0];
39814             } else {
39815               var hours = selected.getHours(),
39816                 minutes = selected.getMinutes(),
39817                 seconds = selected.getSeconds();
39818
39819               if ($scope.showMeridian) {
39820                 hours = hours === 0 || hours === 12 ? 12 : hours % 12; // Convert 24 to 12 hour system
39821               }
39822
39823               $scope.hours = keyboardChange === 'h' ? hours : pad(hours);
39824               if (keyboardChange !== 'm') {
39825                 $scope.minutes = pad(minutes);
39826               }
39827               $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
39828
39829               if (keyboardChange !== 's') {
39830                 $scope.seconds = pad(seconds);
39831               }
39832               $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
39833             }
39834           }
39835
39836           function addSecondsToSelected(seconds) {
39837             selected = addSeconds(selected, seconds);
39838             refresh();
39839           }
39840
39841           function addMinutes(selected, minutes) {
39842             return addSeconds(selected, minutes*60);
39843           }
39844
39845           function addSeconds(date, seconds) {
39846             var dt = new Date(date.getTime() + seconds * 1000);
39847             var newDate = new Date(date);
39848             newDate.setHours(dt.getHours(), dt.getMinutes(), dt.getSeconds());
39849             return newDate;
39850           }
39851
39852           $scope.showSpinners = angular.isDefined($attrs.showSpinners) ?
39853             $scope.$parent.$eval($attrs.showSpinners) : timepickerConfig.showSpinners;
39854
39855           $scope.incrementHours = function() {
39856             if (!$scope.noIncrementHours()) {
39857               addSecondsToSelected(hourStep * 60 * 60);
39858             }
39859           };
39860
39861           $scope.decrementHours = function() {
39862             if (!$scope.noDecrementHours()) {
39863               addSecondsToSelected(-hourStep * 60 * 60);
39864             }
39865           };
39866
39867           $scope.incrementMinutes = function() {
39868             if (!$scope.noIncrementMinutes()) {
39869               addSecondsToSelected(minuteStep * 60);
39870             }
39871           };
39872
39873           $scope.decrementMinutes = function() {
39874             if (!$scope.noDecrementMinutes()) {
39875               addSecondsToSelected(-minuteStep * 60);
39876             }
39877           };
39878
39879           $scope.incrementSeconds = function() {
39880             if (!$scope.noIncrementSeconds()) {
39881               addSecondsToSelected(secondStep);
39882             }
39883           };
39884
39885           $scope.decrementSeconds = function() {
39886             if (!$scope.noDecrementSeconds()) {
39887               addSecondsToSelected(-secondStep);
39888             }
39889           };
39890
39891           $scope.toggleMeridian = function() {
39892             var minutes = getMinutesFromTemplate(),
39893                 hours = getHoursFromTemplate();
39894
39895             if (!$scope.noToggleMeridian()) {
39896               if (angular.isDefined(minutes) && angular.isDefined(hours)) {
39897                 addSecondsToSelected(12 * 60 * (selected.getHours() < 12 ? 60 : -60));
39898               } else {
39899                 $scope.meridian = $scope.meridian === meridians[0] ? meridians[1] : meridians[0];
39900               }
39901             }
39902           };
39903
39904           $scope.blur = function() {
39905             ngModelCtrl.$setTouched();
39906           };
39907         }])
39908
39909         .directive('uibTimepicker', function() {
39910           return {
39911             require: ['uibTimepicker', '?^ngModel'],
39912             controller: 'UibTimepickerController',
39913             controllerAs: 'timepicker',
39914             replace: true,
39915             scope: {},
39916             templateUrl: function(element, attrs) {
39917               return attrs.templateUrl || 'uib/template/timepicker/timepicker.html';
39918             },
39919             link: function(scope, element, attrs, ctrls) {
39920               var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
39921
39922               if (ngModelCtrl) {
39923                 timepickerCtrl.init(ngModelCtrl, element.find('input'));
39924               }
39925             }
39926           };
39927         });
39928
39929         angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap.position'])
39930
39931         /**
39932          * A helper service that can parse typeahead's syntax (string provided by users)
39933          * Extracted to a separate service for ease of unit testing
39934          */
39935           .factory('uibTypeaheadParser', ['$parse', function($parse) {
39936             //                      00000111000000000000022200000000000000003333333333333330000000000044000
39937             var TYPEAHEAD_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;
39938             return {
39939               parse: function(input) {
39940                 var match = input.match(TYPEAHEAD_REGEXP);
39941                 if (!match) {
39942                   throw new Error(
39943                     'Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_"' +
39944                       ' but got "' + input + '".');
39945                 }
39946
39947                 return {
39948                   itemName: match[3],
39949                   source: $parse(match[4]),
39950                   viewMapper: $parse(match[2] || match[1]),
39951                   modelMapper: $parse(match[1])
39952                 };
39953               }
39954             };
39955           }])
39956
39957           .controller('UibTypeaheadController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$q', '$timeout', '$document', '$window', '$rootScope', '$$debounce', '$uibPosition', 'uibTypeaheadParser',
39958             function(originalScope, element, attrs, $compile, $parse, $q, $timeout, $document, $window, $rootScope, $$debounce, $position, typeaheadParser) {
39959             var HOT_KEYS = [9, 13, 27, 38, 40];
39960             var eventDebounceTime = 200;
39961             var modelCtrl, ngModelOptions;
39962             //SUPPORTED ATTRIBUTES (OPTIONS)
39963
39964             //minimal no of characters that needs to be entered before typeahead kicks-in
39965             var minLength = originalScope.$eval(attrs.typeaheadMinLength);
39966             if (!minLength && minLength !== 0) {
39967               minLength = 1;
39968             }
39969
39970             //minimal wait time after last character typed before typeahead kicks-in
39971             var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
39972
39973             //should it restrict model values to the ones selected from the popup only?
39974             var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
39975             originalScope.$watch(attrs.typeaheadEditable, function (newVal) {
39976               isEditable = newVal !== false;
39977             });
39978
39979             //binding to a variable that indicates if matches are being retrieved asynchronously
39980             var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
39981
39982             //a callback executed when a match is selected
39983             var onSelectCallback = $parse(attrs.typeaheadOnSelect);
39984
39985             //should it select highlighted popup value when losing focus?
39986             var isSelectOnBlur = angular.isDefined(attrs.typeaheadSelectOnBlur) ? originalScope.$eval(attrs.typeaheadSelectOnBlur) : false;
39987
39988             //binding to a variable that indicates if there were no results after the query is completed
39989             var isNoResultsSetter = $parse(attrs.typeaheadNoResults).assign || angular.noop;
39990
39991             var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
39992
39993             var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
39994
39995             var appendTo = attrs.typeaheadAppendTo ?
39996               originalScope.$eval(attrs.typeaheadAppendTo) : null;
39997
39998             var focusFirst = originalScope.$eval(attrs.typeaheadFocusFirst) !== false;
39999
40000             //If input matches an item of the list exactly, select it automatically
40001             var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;
40002
40003             //binding to a variable that indicates if dropdown is open
40004             var isOpenSetter = $parse(attrs.typeaheadIsOpen).assign || angular.noop;
40005
40006             var showHint = originalScope.$eval(attrs.typeaheadShowHint) || false;
40007
40008             //INTERNAL VARIABLES
40009
40010             //model setter executed upon match selection
40011             var parsedModel = $parse(attrs.ngModel);
40012             var invokeModelSetter = $parse(attrs.ngModel + '($$$p)');
40013             var $setModelValue = function(scope, newValue) {
40014               if (angular.isFunction(parsedModel(originalScope)) &&
40015                 ngModelOptions && ngModelOptions.$options && ngModelOptions.$options.getterSetter) {
40016                 return invokeModelSetter(scope, {$$$p: newValue});
40017               }
40018
40019               return parsedModel.assign(scope, newValue);
40020             };
40021
40022             //expressions used by typeahead
40023             var parserResult = typeaheadParser.parse(attrs.uibTypeahead);
40024
40025             var hasFocus;
40026
40027             //Used to avoid bug in iOS webview where iOS keyboard does not fire
40028             //mousedown & mouseup events
40029             //Issue #3699
40030             var selected;
40031
40032             //create a child scope for the typeahead directive so we are not polluting original scope
40033             //with typeahead-specific data (matches, query etc.)
40034             var scope = originalScope.$new();
40035             var offDestroy = originalScope.$on('$destroy', function() {
40036               scope.$destroy();
40037             });
40038             scope.$on('$destroy', offDestroy);
40039
40040             // WAI-ARIA
40041             var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
40042             element.attr({
40043               'aria-autocomplete': 'list',
40044               'aria-expanded': false,
40045               'aria-owns': popupId
40046             });
40047
40048             var inputsContainer, hintInputElem;
40049             //add read-only input to show hint
40050             if (showHint) {
40051               inputsContainer = angular.element('<div></div>');
40052               inputsContainer.css('position', 'relative');
40053               element.after(inputsContainer);
40054               hintInputElem = element.clone();
40055               hintInputElem.attr('placeholder', '');
40056               hintInputElem.val('');
40057               hintInputElem.css({
40058                 'position': 'absolute',
40059                 'top': '0px',
40060                 'left': '0px',
40061                 'border-color': 'transparent',
40062                 'box-shadow': 'none',
40063                 'opacity': 1,
40064                 'background': 'none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255)',
40065                 'color': '#999'
40066               });
40067               element.css({
40068                 'position': 'relative',
40069                 'vertical-align': 'top',
40070                 'background-color': 'transparent'
40071               });
40072               inputsContainer.append(hintInputElem);
40073               hintInputElem.after(element);
40074             }
40075
40076             //pop-up element used to display matches
40077             var popUpEl = angular.element('<div uib-typeahead-popup></div>');
40078             popUpEl.attr({
40079               id: popupId,
40080               matches: 'matches',
40081               active: 'activeIdx',
40082               select: 'select(activeIdx, evt)',
40083               'move-in-progress': 'moveInProgress',
40084               query: 'query',
40085               position: 'position',
40086               'assign-is-open': 'assignIsOpen(isOpen)',
40087               debounce: 'debounceUpdate'
40088             });
40089             //custom item template
40090             if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
40091               popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
40092             }
40093
40094             if (angular.isDefined(attrs.typeaheadPopupTemplateUrl)) {
40095               popUpEl.attr('popup-template-url', attrs.typeaheadPopupTemplateUrl);
40096             }
40097
40098             var resetHint = function() {
40099               if (showHint) {
40100                 hintInputElem.val('');
40101               }
40102             };
40103
40104             var resetMatches = function() {
40105               scope.matches = [];
40106               scope.activeIdx = -1;
40107               element.attr('aria-expanded', false);
40108               resetHint();
40109             };
40110
40111             var getMatchId = function(index) {
40112               return popupId + '-option-' + index;
40113             };
40114
40115             // Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
40116             // This attribute is added or removed automatically when the `activeIdx` changes.
40117             scope.$watch('activeIdx', function(index) {
40118               if (index < 0) {
40119                 element.removeAttr('aria-activedescendant');
40120               } else {
40121                 element.attr('aria-activedescendant', getMatchId(index));
40122               }
40123             });
40124
40125             var inputIsExactMatch = function(inputValue, index) {
40126               if (scope.matches.length > index && inputValue) {
40127                 return inputValue.toUpperCase() === scope.matches[index].label.toUpperCase();
40128               }
40129
40130               return false;
40131             };
40132
40133             var getMatchesAsync = function(inputValue, evt) {
40134               var locals = {$viewValue: inputValue};
40135               isLoadingSetter(originalScope, true);
40136               isNoResultsSetter(originalScope, false);
40137               $q.when(parserResult.source(originalScope, locals)).then(function(matches) {
40138                 //it might happen that several async queries were in progress if a user were typing fast
40139                 //but we are interested only in responses that correspond to the current view value
40140                 var onCurrentRequest = inputValue === modelCtrl.$viewValue;
40141                 if (onCurrentRequest && hasFocus) {
40142                   if (matches && matches.length > 0) {
40143                     scope.activeIdx = focusFirst ? 0 : -1;
40144                     isNoResultsSetter(originalScope, false);
40145                     scope.matches.length = 0;
40146
40147                     //transform labels
40148                     for (var i = 0; i < matches.length; i++) {
40149                       locals[parserResult.itemName] = matches[i];
40150                       scope.matches.push({
40151                         id: getMatchId(i),
40152                         label: parserResult.viewMapper(scope, locals),
40153                         model: matches[i]
40154                       });
40155                     }
40156
40157                     scope.query = inputValue;
40158                     //position pop-up with matches - we need to re-calculate its position each time we are opening a window
40159                     //with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
40160                     //due to other elements being rendered
40161                     recalculatePosition();
40162
40163                     element.attr('aria-expanded', true);
40164
40165                     //Select the single remaining option if user input matches
40166                     if (selectOnExact && scope.matches.length === 1 && inputIsExactMatch(inputValue, 0)) {
40167                       if (angular.isNumber(scope.debounceUpdate) || angular.isObject(scope.debounceUpdate)) {
40168                         $$debounce(function() {
40169                           scope.select(0, evt);
40170                         }, angular.isNumber(scope.debounceUpdate) ? scope.debounceUpdate : scope.debounceUpdate['default']);
40171                       } else {
40172                         scope.select(0, evt);
40173                       }
40174                     }
40175
40176                     if (showHint) {
40177                       var firstLabel = scope.matches[0].label;
40178                       if (inputValue.length > 0 && firstLabel.slice(0, inputValue.length).toUpperCase() === inputValue.toUpperCase()) {
40179                         hintInputElem.val(inputValue + firstLabel.slice(inputValue.length));
40180                       }
40181                       else {
40182                         hintInputElem.val('');
40183                       }
40184                     }
40185                   } else {
40186                     resetMatches();
40187                     isNoResultsSetter(originalScope, true);
40188                   }
40189                 }
40190                 if (onCurrentRequest) {
40191                   isLoadingSetter(originalScope, false);
40192                 }
40193               }, function() {
40194                 resetMatches();
40195                 isLoadingSetter(originalScope, false);
40196                 isNoResultsSetter(originalScope, true);
40197               });
40198             };
40199
40200             // bind events only if appendToBody params exist - performance feature
40201             if (appendToBody) {
40202               angular.element($window).on('resize', fireRecalculating);
40203               $document.find('body').on('scroll', fireRecalculating);
40204             }
40205
40206             // Declare the debounced function outside recalculating for
40207             // proper debouncing
40208             var debouncedRecalculate = $$debounce(function() {
40209               // if popup is visible
40210               if (scope.matches.length) {
40211                 recalculatePosition();
40212               }
40213
40214               scope.moveInProgress = false;
40215             }, eventDebounceTime);
40216
40217             // Default progress type
40218             scope.moveInProgress = false;
40219
40220             function fireRecalculating() {
40221               if (!scope.moveInProgress) {
40222                 scope.moveInProgress = true;
40223                 scope.$digest();
40224               }
40225
40226               debouncedRecalculate();
40227             }
40228
40229             // recalculate actual position and set new values to scope
40230             // after digest loop is popup in right position
40231             function recalculatePosition() {
40232               scope.position = appendToBody ? $position.offset(element) : $position.position(element);
40233               scope.position.top += element.prop('offsetHeight');
40234             }
40235
40236             //we need to propagate user's query so we can higlight matches
40237             scope.query = undefined;
40238
40239             //Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
40240             var timeoutPromise;
40241
40242             var scheduleSearchWithTimeout = function(inputValue) {
40243               timeoutPromise = $timeout(function() {
40244                 getMatchesAsync(inputValue);
40245               }, waitTime);
40246             };
40247
40248             var cancelPreviousTimeout = function() {
40249               if (timeoutPromise) {
40250                 $timeout.cancel(timeoutPromise);
40251               }
40252             };
40253
40254             resetMatches();
40255
40256             scope.assignIsOpen = function (isOpen) {
40257               isOpenSetter(originalScope, isOpen);
40258             };
40259
40260             scope.select = function(activeIdx, evt) {
40261               //called from within the $digest() cycle
40262               var locals = {};
40263               var model, item;
40264
40265               selected = true;
40266               locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
40267               model = parserResult.modelMapper(originalScope, locals);
40268               $setModelValue(originalScope, model);
40269               modelCtrl.$setValidity('editable', true);
40270               modelCtrl.$setValidity('parse', true);
40271
40272               onSelectCallback(originalScope, {
40273                 $item: item,
40274                 $model: model,
40275                 $label: parserResult.viewMapper(originalScope, locals),
40276                 $event: evt
40277               });
40278
40279               resetMatches();
40280
40281               //return focus to the input element if a match was selected via a mouse click event
40282               // use timeout to avoid $rootScope:inprog error
40283               if (scope.$eval(attrs.typeaheadFocusOnSelect) !== false) {
40284                 $timeout(function() { element[0].focus(); }, 0, false);
40285               }
40286             };
40287
40288             //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
40289             element.on('keydown', function(evt) {
40290               //typeahead is open and an "interesting" key was pressed
40291               if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
40292                 return;
40293               }
40294
40295               // if there's nothing selected (i.e. focusFirst) and enter or tab is hit, clear the results
40296               if (scope.activeIdx === -1 && (evt.which === 9 || evt.which === 13)) {
40297                 resetMatches();
40298                 scope.$digest();
40299                 return;
40300               }
40301
40302               evt.preventDefault();
40303
40304               switch (evt.which) {
40305                 case 9:
40306                 case 13:
40307                   scope.$apply(function () {
40308                     if (angular.isNumber(scope.debounceUpdate) || angular.isObject(scope.debounceUpdate)) {
40309                       $$debounce(function() {
40310                         scope.select(scope.activeIdx, evt);
40311                       }, angular.isNumber(scope.debounceUpdate) ? scope.debounceUpdate : scope.debounceUpdate['default']);
40312                     } else {
40313                       scope.select(scope.activeIdx, evt);
40314                     }
40315                   });
40316                   break;
40317                 case 27:
40318                   evt.stopPropagation();
40319
40320                   resetMatches();
40321                   scope.$digest();
40322                   break;
40323                 case 38:
40324                   scope.activeIdx = (scope.activeIdx > 0 ? scope.activeIdx : scope.matches.length) - 1;
40325                   scope.$digest();
40326                   popUpEl.find('li')[scope.activeIdx].scrollIntoView(false);
40327                   break;
40328                 case 40:
40329                   scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
40330                   scope.$digest();
40331                   popUpEl.find('li')[scope.activeIdx].scrollIntoView(false);
40332                   break;
40333               }
40334             });
40335
40336             element.bind('focus', function (evt) {
40337               hasFocus = true;
40338               if (minLength === 0 && !modelCtrl.$viewValue) {
40339                 $timeout(function() {
40340                   getMatchesAsync(modelCtrl.$viewValue, evt);
40341                 }, 0);
40342               }
40343             });
40344
40345             element.bind('blur', function(evt) {
40346               if (isSelectOnBlur && scope.matches.length && scope.activeIdx !== -1 && !selected) {
40347                 selected = true;
40348                 scope.$apply(function() {
40349                   if (angular.isObject(scope.debounceUpdate) && angular.isNumber(scope.debounceUpdate.blur)) {
40350                     $$debounce(function() {
40351                       scope.select(scope.activeIdx, evt);
40352                     }, scope.debounceUpdate.blur);
40353                   } else {
40354                     scope.select(scope.activeIdx, evt);
40355                   }
40356                 });
40357               }
40358               if (!isEditable && modelCtrl.$error.editable) {
40359                 modelCtrl.$viewValue = '';
40360                 element.val('');
40361               }
40362               hasFocus = false;
40363               selected = false;
40364             });
40365
40366             // Keep reference to click handler to unbind it.
40367             var dismissClickHandler = function(evt) {
40368               // Issue #3973
40369               // Firefox treats right click as a click on document
40370               if (element[0] !== evt.target && evt.which !== 3 && scope.matches.length !== 0) {
40371                 resetMatches();
40372                 if (!$rootScope.$$phase) {
40373                   scope.$digest();
40374                 }
40375               }
40376             };
40377
40378             $document.on('click', dismissClickHandler);
40379
40380             originalScope.$on('$destroy', function() {
40381               $document.off('click', dismissClickHandler);
40382               if (appendToBody || appendTo) {
40383                 $popup.remove();
40384               }
40385
40386               if (appendToBody) {
40387                 angular.element($window).off('resize', fireRecalculating);
40388                 $document.find('body').off('scroll', fireRecalculating);
40389               }
40390               // Prevent jQuery cache memory leak
40391               popUpEl.remove();
40392
40393               if (showHint) {
40394                   inputsContainer.remove();
40395               }
40396             });
40397
40398             var $popup = $compile(popUpEl)(scope);
40399
40400             if (appendToBody) {
40401               $document.find('body').append($popup);
40402             } else if (appendTo) {
40403               angular.element(appendTo).eq(0).append($popup);
40404             } else {
40405               element.after($popup);
40406             }
40407
40408             this.init = function(_modelCtrl, _ngModelOptions) {
40409               modelCtrl = _modelCtrl;
40410               ngModelOptions = _ngModelOptions;
40411
40412               scope.debounceUpdate = modelCtrl.$options && $parse(modelCtrl.$options.debounce)(originalScope);
40413
40414               //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
40415               //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
40416               modelCtrl.$parsers.unshift(function(inputValue) {
40417                 hasFocus = true;
40418
40419                 if (minLength === 0 || inputValue && inputValue.length >= minLength) {
40420                   if (waitTime > 0) {
40421                     cancelPreviousTimeout();
40422                     scheduleSearchWithTimeout(inputValue);
40423                   } else {
40424                     getMatchesAsync(inputValue);
40425                   }
40426                 } else {
40427                   isLoadingSetter(originalScope, false);
40428                   cancelPreviousTimeout();
40429                   resetMatches();
40430                 }
40431
40432                 if (isEditable) {
40433                   return inputValue;
40434                 }
40435
40436                 if (!inputValue) {
40437                   // Reset in case user had typed something previously.
40438                   modelCtrl.$setValidity('editable', true);
40439                   return null;
40440                 }
40441
40442                 modelCtrl.$setValidity('editable', false);
40443                 return undefined;
40444               });
40445
40446               modelCtrl.$formatters.push(function(modelValue) {
40447                 var candidateViewValue, emptyViewValue;
40448                 var locals = {};
40449
40450                 // The validity may be set to false via $parsers (see above) if
40451                 // the model is restricted to selected values. If the model
40452                 // is set manually it is considered to be valid.
40453                 if (!isEditable) {
40454                   modelCtrl.$setValidity('editable', true);
40455                 }
40456
40457                 if (inputFormatter) {
40458                   locals.$model = modelValue;
40459                   return inputFormatter(originalScope, locals);
40460                 }
40461
40462                 //it might happen that we don't have enough info to properly render input value
40463                 //we need to check for this situation and simply return model value if we can't apply custom formatting
40464                 locals[parserResult.itemName] = modelValue;
40465                 candidateViewValue = parserResult.viewMapper(originalScope, locals);
40466                 locals[parserResult.itemName] = undefined;
40467                 emptyViewValue = parserResult.viewMapper(originalScope, locals);
40468
40469                 return candidateViewValue !== emptyViewValue ? candidateViewValue : modelValue;
40470               });
40471             };
40472           }])
40473
40474           .directive('uibTypeahead', function() {
40475             return {
40476               controller: 'UibTypeaheadController',
40477               require: ['ngModel', '^?ngModelOptions', 'uibTypeahead'],
40478               link: function(originalScope, element, attrs, ctrls) {
40479                 ctrls[2].init(ctrls[0], ctrls[1]);
40480               }
40481             };
40482           })
40483
40484           .directive('uibTypeaheadPopup', ['$$debounce', function($$debounce) {
40485             return {
40486               scope: {
40487                 matches: '=',
40488                 query: '=',
40489                 active: '=',
40490                 position: '&',
40491                 moveInProgress: '=',
40492                 select: '&',
40493                 assignIsOpen: '&',
40494                 debounce: '&'
40495               },
40496               replace: true,
40497               templateUrl: function(element, attrs) {
40498                 return attrs.popupTemplateUrl || 'uib/template/typeahead/typeahead-popup.html';
40499               },
40500               link: function(scope, element, attrs) {
40501                 scope.templateUrl = attrs.templateUrl;
40502
40503                 scope.isOpen = function() {
40504                   var isDropdownOpen = scope.matches.length > 0;
40505                   scope.assignIsOpen({ isOpen: isDropdownOpen });
40506                   return isDropdownOpen;
40507                 };
40508
40509                 scope.isActive = function(matchIdx) {
40510                   return scope.active === matchIdx;
40511                 };
40512
40513                 scope.selectActive = function(matchIdx) {
40514                   scope.active = matchIdx;
40515                 };
40516
40517                 scope.selectMatch = function(activeIdx, evt) {
40518                   var debounce = scope.debounce();
40519                   if (angular.isNumber(debounce) || angular.isObject(debounce)) {
40520                     $$debounce(function() {
40521                       scope.select({activeIdx: activeIdx, evt: evt});
40522                     }, angular.isNumber(debounce) ? debounce : debounce['default']);
40523                   } else {
40524                     scope.select({activeIdx: activeIdx, evt: evt});
40525                   }
40526                 };
40527               }
40528             };
40529           }])
40530
40531           .directive('uibTypeaheadMatch', ['$templateRequest', '$compile', '$parse', function($templateRequest, $compile, $parse) {
40532             return {
40533               scope: {
40534                 index: '=',
40535                 match: '=',
40536                 query: '='
40537               },
40538               link: function(scope, element, attrs) {
40539                 var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'uib/template/typeahead/typeahead-match.html';
40540                 $templateRequest(tplUrl).then(function(tplContent) {
40541                   var tplEl = angular.element(tplContent.trim());
40542                   element.replaceWith(tplEl);
40543                   $compile(tplEl)(scope);
40544                 });
40545               }
40546             };
40547           }])
40548
40549           .filter('uibTypeaheadHighlight', ['$sce', '$injector', '$log', function($sce, $injector, $log) {
40550             var isSanitizePresent;
40551             isSanitizePresent = $injector.has('$sanitize');
40552
40553             function escapeRegexp(queryToEscape) {
40554               // Regex: capture the whole query string and replace it with the string that will be used to match
40555               // the results, for example if the capture is "a" the result will be \a
40556               return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
40557             }
40558
40559             function containsHtml(matchItem) {
40560               return /<.*>/g.test(matchItem);
40561             }
40562
40563             return function(matchItem, query) {
40564               if (!isSanitizePresent && containsHtml(matchItem)) {
40565                 $log.warn('Unsafe use of typeahead please use ngSanitize'); // Warn the user about the danger
40566               }
40567               matchItem = query ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem; // Replaces the capture string with a the same string inside of a "strong" tag
40568               if (!isSanitizePresent) {
40569                 matchItem = $sce.trustAsHtml(matchItem); // If $sanitize is not present we pack the string in a $sce object for the ng-bind-html directive
40570               }
40571               return matchItem;
40572             };
40573           }]);
40574
40575         angular.module("uib/template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
40576           $templateCache.put("uib/template/accordion/accordion-group.html",
40577             "<div class=\"panel\" ng-class=\"panelClass || 'panel-default'\">\n" +
40578             "  <div class=\"panel-heading\" ng-keypress=\"toggleOpen($event)\">\n" +
40579             "    <h4 class=\"panel-title\">\n" +
40580             "      <div tabindex=\"0\" class=\"accordion-toggle\" ng-click=\"toggleOpen()\" uib-accordion-transclude=\"heading\"><span ng-class=\"{'text-muted': isDisabled}\">{{heading}}</span></div>\n" +
40581             "    </h4>\n" +
40582             "  </div>\n" +
40583             "  <div class=\"panel-collapse collapse\" uib-collapse=\"!isOpen\">\n" +
40584             "     <div class=\"panel-body\" ng-transclude></div>\n" +
40585             "  </div>\n" +
40586             "</div>\n" +
40587             "");
40588         }]);
40589
40590         angular.module("uib/template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
40591           $templateCache.put("uib/template/accordion/accordion.html",
40592             "<div class=\"panel-group\" ng-transclude></div>");
40593         }]);
40594
40595         angular.module("uib/template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
40596           $templateCache.put("uib/template/alert/alert.html",
40597             "<div class=\"alert\" ng-class=\"['alert-' + (type || 'warning'), closeable ? 'alert-dismissible' : null]\" role=\"alert\">\n" +
40598             "    <button ng-show=\"closeable\" type=\"button\" class=\"close\" ng-click=\"close({$event: $event})\">\n" +
40599             "        <span aria-hidden=\"true\">&times;</span>\n" +
40600             "        <span class=\"sr-only\">Close</span>\n" +
40601             "    </button>\n" +
40602             "    <div ng-transclude></div>\n" +
40603             "</div>\n" +
40604             "");
40605         }]);
40606
40607         angular.module("uib/template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) {
40608           $templateCache.put("uib/template/carousel/carousel.html",
40609             "<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\">\n" +
40610             "  <div class=\"carousel-inner\" ng-transclude></div>\n" +
40611             "  <a role=\"button\" href class=\"left carousel-control\" ng-click=\"prev()\" ng-show=\"slides.length > 1\">\n" +
40612             "    <span aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-left\"></span>\n" +
40613             "    <span class=\"sr-only\">previous</span>\n" +
40614             "  </a>\n" +
40615             "  <a role=\"button\" href class=\"right carousel-control\" ng-click=\"next()\" ng-show=\"slides.length > 1\">\n" +
40616             "    <span aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-right\"></span>\n" +
40617             "    <span class=\"sr-only\">next</span>\n" +
40618             "  </a>\n" +
40619             "  <ol class=\"carousel-indicators\" ng-show=\"slides.length > 1\">\n" +
40620             "    <li ng-repeat=\"slide in slides | orderBy:indexOfSlide track by $index\" ng-class=\"{ active: isActive(slide) }\" ng-click=\"select(slide)\">\n" +
40621             "      <span class=\"sr-only\">slide {{ $index + 1 }} of {{ slides.length }}<span ng-if=\"isActive(slide)\">, currently active</span></span>\n" +
40622             "    </li>\n" +
40623             "  </ol>\n" +
40624             "</div>");
40625         }]);
40626
40627         angular.module("uib/template/carousel/slide.html", []).run(["$templateCache", function($templateCache) {
40628           $templateCache.put("uib/template/carousel/slide.html",
40629             "<div ng-class=\"{\n" +
40630             "    'active': active\n" +
40631             "  }\" class=\"item text-center\" ng-transclude></div>\n" +
40632             "");
40633         }]);
40634
40635         angular.module("uib/template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
40636           $templateCache.put("uib/template/datepicker/datepicker.html",
40637             "<div class=\"uib-datepicker\" ng-switch=\"datepickerMode\" role=\"application\" ng-keydown=\"keydown($event)\">\n" +
40638             "  <uib-daypicker ng-switch-when=\"day\" tabindex=\"0\"></uib-daypicker>\n" +
40639             "  <uib-monthpicker ng-switch-when=\"month\" tabindex=\"0\"></uib-monthpicker>\n" +
40640             "  <uib-yearpicker ng-switch-when=\"year\" tabindex=\"0\"></uib-yearpicker>\n" +
40641             "</div>");
40642         }]);
40643
40644         angular.module("uib/template/datepicker/day.html", []).run(["$templateCache", function($templateCache) {
40645           $templateCache.put("uib/template/datepicker/day.html",
40646             "<table class=\"uib-daypicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
40647             "  <thead>\n" +
40648             "    <tr>\n" +
40649             "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
40650             "      <th colspan=\"{{::5 + showWeeks}}\"><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
40651             "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
40652             "    </tr>\n" +
40653             "    <tr>\n" +
40654             "      <th ng-if=\"showWeeks\" class=\"text-center\"></th>\n" +
40655             "      <th ng-repeat=\"label in ::labels track by $index\" class=\"text-center\"><small aria-label=\"{{::label.full}}\">{{::label.abbr}}</small></th>\n" +
40656             "    </tr>\n" +
40657             "  </thead>\n" +
40658             "  <tbody>\n" +
40659             "    <tr class=\"uib-weeks\" ng-repeat=\"row in rows track by $index\">\n" +
40660             "      <td ng-if=\"showWeeks\" class=\"text-center h6\"><em>{{ weekNumbers[$index] }}</em></td>\n" +
40661             "      <td ng-repeat=\"dt in row\" class=\"uib-day text-center\" role=\"gridcell\"\n" +
40662             "        id=\"{{::dt.uid}}\"\n" +
40663             "        ng-class=\"::dt.customClass\">\n" +
40664             "        <button type=\"button\" style=\"min-width:100%;\" class=\"btn btn-default btn-sm\"\n" +
40665             "          uib-is-class=\"\n" +
40666             "            'btn-info' for selectedDt,\n" +
40667             "            'active' for activeDt\n" +
40668             "            on dt\"\n" +
40669             "          ng-click=\"select(dt.date)\"\n" +
40670             "          ng-disabled=\"::dt.disabled\"\n" +
40671             "          tabindex=\"-1\"><span ng-class=\"::{'text-muted': dt.secondary, 'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
40672             "      </td>\n" +
40673             "    </tr>\n" +
40674             "  </tbody>\n" +
40675             "</table>\n" +
40676             "");
40677         }]);
40678
40679         angular.module("uib/template/datepicker/month.html", []).run(["$templateCache", function($templateCache) {
40680           $templateCache.put("uib/template/datepicker/month.html",
40681             "<table class=\"uib-monthpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
40682             "  <thead>\n" +
40683             "    <tr>\n" +
40684             "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
40685             "      <th><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
40686             "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
40687             "    </tr>\n" +
40688             "  </thead>\n" +
40689             "  <tbody>\n" +
40690             "    <tr class=\"uib-months\" ng-repeat=\"row in rows track by $index\">\n" +
40691             "      <td ng-repeat=\"dt in row\" class=\"uib-month text-center\" role=\"gridcell\"\n" +
40692             "        id=\"{{::dt.uid}}\"\n" +
40693             "        ng-class=\"::dt.customClass\">\n" +
40694             "        <button type=\"button\" style=\"min-width:100%;\" class=\"btn btn-default\"\n" +
40695             "          uib-is-class=\"\n" +
40696             "            'btn-info' for selectedDt,\n" +
40697             "            'active' for activeDt\n" +
40698             "            on dt\"\n" +
40699             "          ng-click=\"select(dt.date)\"\n" +
40700             "          ng-disabled=\"::dt.disabled\"\n" +
40701             "          tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
40702             "      </td>\n" +
40703             "    </tr>\n" +
40704             "  </tbody>\n" +
40705             "</table>\n" +
40706             "");
40707         }]);
40708
40709         angular.module("uib/template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) {
40710           $templateCache.put("uib/template/datepicker/popup.html",
40711             "<ul class=\"uib-datepicker-popup dropdown-menu\" dropdown-nested ng-if=\"isOpen\" style=\"display: block\" ng-style=\"{top: position.top+'px', left: position.left+'px'}\" ng-keydown=\"keydown($event)\" ng-click=\"$event.stopPropagation()\">\n" +
40712             "   <li ng-transclude></li>\n" +
40713             "   <li ng-if=\"showButtonBar\" style=\"padding:10px 9px 2px\" class=\"uib-button-bar\">\n" +
40714             "           <span class=\"btn-group pull-left\">\n" +
40715             "                   <button type=\"button\" class=\"btn btn-sm btn-info uib-datepicker-current\" ng-click=\"select('today')\" ng-disabled=\"isDisabled('today')\">{{ getText('current') }}</button>\n" +
40716             "                   <button type=\"button\" class=\"btn btn-sm btn-danger uib-clear\" ng-click=\"select(null)\">{{ getText('clear') }}</button>\n" +
40717             "           </span>\n" +
40718             "           <button type=\"button\" class=\"btn btn-sm btn-success pull-right uib-close\" ng-click=\"close()\">{{ getText('close') }}</button>\n" +
40719             "   </li>\n" +
40720             "</ul>\n" +
40721             "");
40722         }]);
40723
40724         angular.module("uib/template/datepicker/year.html", []).run(["$templateCache", function($templateCache) {
40725           $templateCache.put("uib/template/datepicker/year.html",
40726             "<table class=\"uib-yearpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
40727             "  <thead>\n" +
40728             "    <tr>\n" +
40729             "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
40730             "      <th colspan=\"{{::columns - 2}}\"><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
40731             "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
40732             "    </tr>\n" +
40733             "  </thead>\n" +
40734             "  <tbody>\n" +
40735             "    <tr class=\"uib-years\" ng-repeat=\"row in rows track by $index\">\n" +
40736             "      <td ng-repeat=\"dt in row\" class=\"uib-year text-center\" role=\"gridcell\"\n" +
40737             "        id=\"{{::dt.uid}}\"\n" +
40738             "        ng-class=\"::dt.customClass\">\n" +
40739             "        <button type=\"button\" style=\"min-width:100%;\" class=\"btn btn-default\"\n" +
40740             "          uib-is-class=\"\n" +
40741             "            'btn-info' for selectedDt,\n" +
40742             "            'active' for activeDt\n" +
40743             "            on dt\"\n" +
40744             "          ng-click=\"select(dt.date)\"\n" +
40745             "          ng-disabled=\"::dt.disabled\"\n" +
40746             "          tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
40747             "      </td>\n" +
40748             "    </tr>\n" +
40749             "  </tbody>\n" +
40750             "</table>\n" +
40751             "");
40752         }]);
40753
40754         angular.module("uib/template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
40755           $templateCache.put("uib/template/modal/backdrop.html",
40756             "<div class=\"modal-backdrop\"\n" +
40757             "     uib-modal-animation-class=\"fade\"\n" +
40758             "     modal-in-class=\"in\"\n" +
40759             "     ng-style=\"{'z-index': 1040 + (index && 1 || 0) + index*10}\"\n" +
40760             "></div>\n" +
40761             "");
40762         }]);
40763
40764         angular.module("uib/template/modal/window.html", []).run(["$templateCache", function($templateCache) {
40765           $templateCache.put("uib/template/modal/window.html",
40766             "<div modal-render=\"{{$isRendered}}\" tabindex=\"-1\" role=\"dialog\" class=\"modal\"\n" +
40767             "    uib-modal-animation-class=\"fade\"\n" +
40768             "    modal-in-class=\"in\"\n" +
40769             "    ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\">\n" +
40770             "    <div class=\"modal-dialog\" ng-class=\"size ? 'modal-' + size : ''\"><div class=\"modal-content\" uib-modal-transclude></div></div>\n" +
40771             "</div>\n" +
40772             "");
40773         }]);
40774
40775         angular.module("uib/template/pager/pager.html", []).run(["$templateCache", function($templateCache) {
40776           $templateCache.put("uib/template/pager/pager.html",
40777             "<ul class=\"pager\">\n" +
40778             "  <li ng-class=\"{disabled: noPrevious()||ngDisabled, previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
40779             "  <li ng-class=\"{disabled: noNext()||ngDisabled, next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
40780             "</ul>\n" +
40781             "");
40782         }]);
40783
40784         angular.module("uib/template/pagination/pager.html", []).run(["$templateCache", function($templateCache) {
40785           $templateCache.put("uib/template/pagination/pager.html",
40786             "<ul class=\"pager\">\n" +
40787             "  <li ng-class=\"{disabled: noPrevious()||ngDisabled, previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
40788             "  <li ng-class=\"{disabled: noNext()||ngDisabled, next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
40789             "</ul>\n" +
40790             "");
40791         }]);
40792
40793         angular.module("uib/template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
40794           $templateCache.put("uib/template/pagination/pagination.html",
40795             "<ul class=\"pagination\">\n" +
40796             "  <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noPrevious()||ngDisabled}\" class=\"pagination-first\"><a href ng-click=\"selectPage(1, $event)\">{{::getText('first')}}</a></li>\n" +
40797             "  <li ng-if=\"::directionLinks\" ng-class=\"{disabled: noPrevious()||ngDisabled}\" class=\"pagination-prev\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
40798             "  <li ng-repeat=\"page in pages track by $index\" ng-class=\"{active: page.active,disabled: ngDisabled&&!page.active}\" class=\"pagination-page\"><a href ng-click=\"selectPage(page.number, $event)\">{{page.text}}</a></li>\n" +
40799             "  <li ng-if=\"::directionLinks\" ng-class=\"{disabled: noNext()||ngDisabled}\" class=\"pagination-next\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
40800             "  <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noNext()||ngDisabled}\" class=\"pagination-last\"><a href ng-click=\"selectPage(totalPages, $event)\">{{::getText('last')}}</a></li>\n" +
40801             "</ul>\n" +
40802             "");
40803         }]);
40804
40805         angular.module("uib/template/tooltip/tooltip-html-popup.html", []).run(["$templateCache", function($templateCache) {
40806           $templateCache.put("uib/template/tooltip/tooltip-html-popup.html",
40807             "<div class=\"tooltip\"\n" +
40808             "  tooltip-animation-class=\"fade\"\n" +
40809             "  uib-tooltip-classes\n" +
40810             "  ng-class=\"{ in: isOpen() }\">\n" +
40811             "  <div class=\"tooltip-arrow\"></div>\n" +
40812             "  <div class=\"tooltip-inner\" ng-bind-html=\"contentExp()\"></div>\n" +
40813             "</div>\n" +
40814             "");
40815         }]);
40816
40817         angular.module("uib/template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
40818           $templateCache.put("uib/template/tooltip/tooltip-popup.html",
40819             "<div class=\"tooltip\"\n" +
40820             "  tooltip-animation-class=\"fade\"\n" +
40821             "  uib-tooltip-classes\n" +
40822             "  ng-class=\"{ in: isOpen() }\">\n" +
40823             "  <div class=\"tooltip-arrow\"></div>\n" +
40824             "  <div class=\"tooltip-inner\" ng-bind=\"content\"></div>\n" +
40825             "</div>\n" +
40826             "");
40827         }]);
40828
40829         angular.module("uib/template/tooltip/tooltip-template-popup.html", []).run(["$templateCache", function($templateCache) {
40830           $templateCache.put("uib/template/tooltip/tooltip-template-popup.html",
40831             "<div class=\"tooltip\"\n" +
40832             "  tooltip-animation-class=\"fade\"\n" +
40833             "  uib-tooltip-classes\n" +
40834             "  ng-class=\"{ in: isOpen() }\">\n" +
40835             "  <div class=\"tooltip-arrow\"></div>\n" +
40836             "  <div class=\"tooltip-inner\"\n" +
40837             "    uib-tooltip-template-transclude=\"contentExp()\"\n" +
40838             "    tooltip-template-transclude-scope=\"originScope()\"></div>\n" +
40839             "</div>\n" +
40840             "");
40841         }]);
40842
40843         angular.module("uib/template/popover/popover-html.html", []).run(["$templateCache", function($templateCache) {
40844           $templateCache.put("uib/template/popover/popover-html.html",
40845             "<div class=\"popover\"\n" +
40846             "  tooltip-animation-class=\"fade\"\n" +
40847             "  uib-tooltip-classes\n" +
40848             "  ng-class=\"{ in: isOpen() }\">\n" +
40849             "  <div class=\"arrow\"></div>\n" +
40850             "\n" +
40851             "  <div class=\"popover-inner\">\n" +
40852             "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-if=\"title\"></h3>\n" +
40853             "      <div class=\"popover-content\" ng-bind-html=\"contentExp()\"></div>\n" +
40854             "  </div>\n" +
40855             "</div>\n" +
40856             "");
40857         }]);
40858
40859         angular.module("uib/template/popover/popover-template.html", []).run(["$templateCache", function($templateCache) {
40860           $templateCache.put("uib/template/popover/popover-template.html",
40861             "<div class=\"popover\"\n" +
40862             "  tooltip-animation-class=\"fade\"\n" +
40863             "  uib-tooltip-classes\n" +
40864             "  ng-class=\"{ in: isOpen() }\">\n" +
40865             "  <div class=\"arrow\"></div>\n" +
40866             "\n" +
40867             "  <div class=\"popover-inner\">\n" +
40868             "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-if=\"title\"></h3>\n" +
40869             "      <div class=\"popover-content\"\n" +
40870             "        uib-tooltip-template-transclude=\"contentExp()\"\n" +
40871             "        tooltip-template-transclude-scope=\"originScope()\"></div>\n" +
40872             "  </div>\n" +
40873             "</div>\n" +
40874             "");
40875         }]);
40876
40877         angular.module("uib/template/popover/popover.html", []).run(["$templateCache", function($templateCache) {
40878           $templateCache.put("uib/template/popover/popover.html",
40879             "<div class=\"popover\"\n" +
40880             "  tooltip-animation-class=\"fade\"\n" +
40881             "  uib-tooltip-classes\n" +
40882             "  ng-class=\"{ in: isOpen() }\">\n" +
40883             "  <div class=\"arrow\"></div>\n" +
40884             "\n" +
40885             "  <div class=\"popover-inner\">\n" +
40886             "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-if=\"title\"></h3>\n" +
40887             "      <div class=\"popover-content\" ng-bind=\"content\"></div>\n" +
40888             "  </div>\n" +
40889             "</div>\n" +
40890             "");
40891         }]);
40892
40893         angular.module("uib/template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) {
40894           $templateCache.put("uib/template/progressbar/bar.html",
40895             "<div class=\"progress-bar\" ng-class=\"type && 'progress-bar-' + type\" role=\"progressbar\" aria-valuenow=\"{{value}}\" aria-valuemin=\"0\" aria-valuemax=\"{{max}}\" ng-style=\"{width: (percent < 100 ? percent : 100) + '%'}\" aria-valuetext=\"{{percent | number:0}}%\" aria-labelledby=\"{{::title}}\" ng-transclude></div>\n" +
40896             "");
40897         }]);
40898
40899         angular.module("uib/template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) {
40900           $templateCache.put("uib/template/progressbar/progress.html",
40901             "<div class=\"progress\" ng-transclude aria-labelledby=\"{{::title}}\"></div>");
40902         }]);
40903
40904         angular.module("uib/template/progressbar/progressbar.html", []).run(["$templateCache", function($templateCache) {
40905           $templateCache.put("uib/template/progressbar/progressbar.html",
40906             "<div class=\"progress\">\n" +
40907             "  <div class=\"progress-bar\" ng-class=\"type && 'progress-bar-' + type\" role=\"progressbar\" aria-valuenow=\"{{value}}\" aria-valuemin=\"0\" aria-valuemax=\"{{max}}\" ng-style=\"{width: (percent < 100 ? percent : 100) + '%'}\" aria-valuetext=\"{{percent | number:0}}%\" aria-labelledby=\"{{::title}}\" ng-transclude></div>\n" +
40908             "</div>\n" +
40909             "");
40910         }]);
40911
40912         angular.module("uib/template/rating/rating.html", []).run(["$templateCache", function($templateCache) {
40913           $templateCache.put("uib/template/rating/rating.html",
40914             "<span ng-mouseleave=\"reset()\" ng-keydown=\"onKeydown($event)\" tabindex=\"0\" role=\"slider\" aria-valuemin=\"0\" aria-valuemax=\"{{range.length}}\" aria-valuenow=\"{{value}}\">\n" +
40915             "    <span ng-repeat-start=\"r in range track by $index\" class=\"sr-only\">({{ $index < value ? '*' : ' ' }})</span>\n" +
40916             "    <i ng-repeat-end ng-mouseenter=\"enter($index + 1)\" ng-click=\"rate($index + 1)\" class=\"glyphicon\" ng-class=\"$index < value && (r.stateOn || 'glyphicon-star') || (r.stateOff || 'glyphicon-star-empty')\" ng-attr-title=\"{{r.title}}\" aria-valuetext=\"{{r.title}}\"></i>\n" +
40917             "</span>\n" +
40918             "");
40919         }]);
40920
40921         angular.module("uib/template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
40922           $templateCache.put("uib/template/tabs/tab.html",
40923             "<li ng-class=\"{active: active, disabled: disabled}\" class=\"uib-tab\">\n" +
40924             "  <div ng-click=\"select()\" uib-tab-heading-transclude>{{heading}}</div>\n" +
40925             "</li>\n" +
40926             "");
40927         }]);
40928
40929         angular.module("uib/template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
40930           $templateCache.put("uib/template/tabs/tabset.html",
40931             "<div>\n" +
40932             "  <ul class=\"nav nav-{{type || 'tabs'}}\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
40933             "  <div class=\"tab-content\">\n" +
40934             "    <div class=\"tab-pane\" \n" +
40935             "         ng-repeat=\"tab in tabs\" \n" +
40936             "         ng-class=\"{active: tab.active}\"\n" +
40937             "         uib-tab-content-transclude=\"tab\">\n" +
40938             "    </div>\n" +
40939             "  </div>\n" +
40940             "</div>\n" +
40941             "");
40942         }]);
40943
40944         angular.module("uib/template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) {
40945           $templateCache.put("uib/template/timepicker/timepicker.html",
40946             "<table class=\"uib-timepicker\">\n" +
40947             "  <tbody>\n" +
40948             "    <tr class=\"text-center\" ng-show=\"::showSpinners\">\n" +
40949             "      <td class=\"uib-increment hours\"><a ng-click=\"incrementHours()\" ng-class=\"{disabled: noIncrementHours()}\" class=\"btn btn-link\" ng-disabled=\"noIncrementHours()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
40950             "      <td>&nbsp;</td>\n" +
40951             "      <td class=\"uib-increment minutes\"><a ng-click=\"incrementMinutes()\" ng-class=\"{disabled: noIncrementMinutes()}\" class=\"btn btn-link\" ng-disabled=\"noIncrementMinutes()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
40952             "      <td ng-show=\"showSeconds\">&nbsp;</td>\n" +
40953             "      <td ng-show=\"showSeconds\" class=\"uib-increment seconds\"><a ng-click=\"incrementSeconds()\" ng-class=\"{disabled: noIncrementSeconds()}\" class=\"btn btn-link\" ng-disabled=\"noIncrementSeconds()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
40954             "      <td ng-show=\"showMeridian\"></td>\n" +
40955             "    </tr>\n" +
40956             "    <tr>\n" +
40957             "      <td class=\"form-group uib-time hours\" ng-class=\"{'has-error': invalidHours}\">\n" +
40958             "        <input style=\"width:50px;\" type=\"text\" placeholder=\"HH\" ng-model=\"hours\" ng-change=\"updateHours()\" class=\"form-control text-center\" ng-readonly=\"::readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"disabled\" ng-blur=\"blur()\">\n" +
40959             "      </td>\n" +
40960             "      <td class=\"uib-separator\">:</td>\n" +
40961             "      <td class=\"form-group uib-time minutes\" ng-class=\"{'has-error': invalidMinutes}\">\n" +
40962             "        <input style=\"width:50px;\" type=\"text\" placeholder=\"MM\" ng-model=\"minutes\" ng-change=\"updateMinutes()\" class=\"form-control text-center\" ng-readonly=\"::readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"disabled\" ng-blur=\"blur()\">\n" +
40963             "      </td>\n" +
40964             "      <td ng-show=\"showSeconds\" class=\"uib-separator\">:</td>\n" +
40965             "      <td class=\"form-group uib-time seconds\" ng-class=\"{'has-error': invalidSeconds}\" ng-show=\"showSeconds\">\n" +
40966             "        <input style=\"width:50px;\" type=\"text\" ng-model=\"seconds\" ng-change=\"updateSeconds()\" class=\"form-control text-center\" ng-readonly=\"readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"disabled\" ng-blur=\"blur()\">\n" +
40967             "      </td>\n" +
40968             "      <td ng-show=\"showMeridian\" class=\"uib-time am-pm\"><button type=\"button\" ng-class=\"{disabled: noToggleMeridian()}\" class=\"btn btn-default text-center\" ng-click=\"toggleMeridian()\" ng-disabled=\"noToggleMeridian()\" tabindex=\"{{::tabindex}}\">{{meridian}}</button></td>\n" +
40969             "    </tr>\n" +
40970             "    <tr class=\"text-center\" ng-show=\"::showSpinners\">\n" +
40971             "      <td class=\"uib-decrement hours\"><a ng-click=\"decrementHours()\" ng-class=\"{disabled: noDecrementHours()}\" class=\"btn btn-link\" ng-disabled=\"noDecrementHours()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
40972             "      <td>&nbsp;</td>\n" +
40973             "      <td class=\"uib-decrement minutes\"><a ng-click=\"decrementMinutes()\" ng-class=\"{disabled: noDecrementMinutes()}\" class=\"btn btn-link\" ng-disabled=\"noDecrementMinutes()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
40974             "      <td ng-show=\"showSeconds\">&nbsp;</td>\n" +
40975             "      <td ng-show=\"showSeconds\" class=\"uib-decrement seconds\"><a ng-click=\"decrementSeconds()\" ng-class=\"{disabled: noDecrementSeconds()}\" class=\"btn btn-link\" ng-disabled=\"noDecrementSeconds()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
40976             "      <td ng-show=\"showMeridian\"></td>\n" +
40977             "    </tr>\n" +
40978             "  </tbody>\n" +
40979             "</table>\n" +
40980             "");
40981         }]);
40982
40983         angular.module("uib/template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
40984           $templateCache.put("uib/template/typeahead/typeahead-match.html",
40985             "<a href tabindex=\"-1\" ng-bind-html=\"match.label | uibTypeaheadHighlight:query\"></a>\n" +
40986             "");
40987         }]);
40988
40989         angular.module("uib/template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) {
40990           $templateCache.put("uib/template/typeahead/typeahead-popup.html",
40991             "<ul class=\"dropdown-menu\" ng-show=\"isOpen() && !moveInProgress\" ng-style=\"{top: position().top+'px', left: position().left+'px'}\" style=\"display: block;\" role=\"listbox\" aria-hidden=\"{{!isOpen()}}\">\n" +
40992             "    <li ng-repeat=\"match in matches track by $index\" ng-class=\"{active: isActive($index) }\" ng-mouseenter=\"selectActive($index)\" ng-click=\"selectMatch($index, $event)\" role=\"option\" id=\"{{::match.id}}\">\n" +
40993             "        <div uib-typeahead-match index=\"$index\" match=\"match\" query=\"query\" template-url=\"templateUrl\"></div>\n" +
40994             "    </li>\n" +
40995             "</ul>\n" +
40996             "");
40997         }]);
40998         angular.module('ui.bootstrap.carousel').run(function() {!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">.ng-animate.item:not(.left):not(.right){-webkit-transition:0s ease-in-out left;transition:0s ease-in-out left}</style>'); })
40999
41000 /***/ },
41001 /* 8 */
41002 /***/ function(module, exports) {
41003
41004         var app;
41005         (function (app) {
41006             var declares;
41007             (function (declares) {
41008                 var CommandInfo = (function () {
41009                     function CommandInfo(name) {
41010                         this.name = name;
41011                     }
41012                     return CommandInfo;
41013                 })();
41014                 declares.CommandInfo = CommandInfo;
41015             })(declares = app.declares || (app.declares = {}));
41016         })(app || (app = {}));
41017         var app;
41018         (function (app) {
41019             var services;
41020             (function (services) {
41021                 var APIEndPoint = (function () {
41022                     function APIEndPoint($resource, $http) {
41023                         this.$resource = $resource;
41024                         this.$http = $http;
41025                     }
41026                     APIEndPoint.prototype.resource = function (endPoint, data) {
41027                         var customAction = {
41028                             method: 'GET',
41029                             isArray: false
41030                         };
41031                         var execute = {
41032                             method: 'POST',
41033                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
41034                         };
41035                         return this.$resource(endPoint, {}, { execute: execute });
41036                     };
41037                     APIEndPoint.prototype.getOptionControlFile = function (command) {
41038                         var endPoint = '/api/v1/optionControlFile/' + command;
41039                         return this.resource(endPoint, {}).get();
41040                     };
41041                     APIEndPoint.prototype.getFiles = function (fileId) {
41042                         var endPoint = '/api/v1/workspace';
41043                         if (fileId) {
41044                             endPoint += '/' + fileId;
41045                         }
41046                         return this.resource(endPoint, {}).get();
41047                     };
41048                     APIEndPoint.prototype.getDirectories = function () {
41049                         var endPoint = '/api/v1/all/workspace/directory';
41050                         return this.resource(endPoint, {}).get();
41051                     };
41052                     APIEndPoint.prototype.getTags = function () {
41053                         var endPoint = '/api/v1/tagList';
41054                         return this.resource(endPoint, {}).get();
41055                     };
41056                     APIEndPoint.prototype.getCommands = function () {
41057                         var endPoint = '/api/v1/commandList';
41058                         return this.resource(endPoint, {}).get();
41059                     };
41060                     APIEndPoint.prototype.execute = function (data) {
41061                         var endPoint = '/api/v1/execution';
41062                         var fd = new FormData();
41063                         fd.append('data', data);
41064                         return this.$http.post(endPoint, fd, {
41065                             headers: { 'Content-Type': undefined },
41066                             transformRequest: angular.identity
41067                         });
41068                     };
41069                     APIEndPoint.prototype.debug = function () {
41070                         var endPoint = '/api/v1/debug';
41071                         return this.$http.get(endPoint);
41072                     };
41073                     APIEndPoint.prototype.help = function (command) {
41074                         var endPoint = '/api/v1/help/' + command;
41075                         return this.$http.get(endPoint);
41076                     };
41077                     return APIEndPoint;
41078                 })();
41079                 services.APIEndPoint = APIEndPoint;
41080             })(services = app.services || (app.services = {}));
41081         })(app || (app = {}));
41082         var app;
41083         (function (app) {
41084             var services;
41085             (function (services) {
41086                 var MyModal = (function () {
41087                     function MyModal($uibModal) {
41088                         this.$uibModal = $uibModal;
41089                         this.modalOption = {
41090                             backdrop: true,
41091                             controller: null,
41092                             templateUrl: null,
41093                             size: null
41094                         };
41095                     }
41096                     MyModal.prototype.open = function (modalName) {
41097                         if (modalName === 'SelectCommand') {
41098                             this.modalOption.templateUrl = 'templates/select-command.html';
41099                             this.modalOption.size = 'lg';
41100                         }
41101                         return this.$uibModal.open(this.modalOption);
41102                     };
41103                     MyModal.prototype.selectCommand = function () {
41104                         this.modalOption.templateUrl = 'templates/select-command.html';
41105                         this.modalOption.controller = 'selectCommandController';
41106                         this.modalOption.controllerAs = 'c';
41107                         this.modalOption.size = 'lg';
41108                         return this.$uibModal.open(this.modalOption);
41109                     };
41110                     MyModal.prototype.preview = function () {
41111                         this.modalOption.templateUrl = 'templates/preview.html';
41112                         this.modalOption.controller = 'previewController';
41113                         this.modalOption.controllerAs = 'c';
41114                         this.modalOption.size = 'lg';
41115                         return this.$uibModal.open(this.modalOption);
41116                     };
41117                     MyModal.$inject = ['$uibModal'];
41118                     return MyModal;
41119                 })();
41120                 services.MyModal = MyModal;
41121             })(services = app.services || (app.services = {}));
41122         })(app || (app = {}));
41123         var app;
41124         (function (app) {
41125             var services;
41126             (function (services) {
41127                 var WebSocket = (function () {
41128                     function WebSocket($rootScope) {
41129                         this.$rootScope = $rootScope;
41130                         this.socket = io.connect();
41131                     }
41132                     WebSocket.prototype.on = function (eventName, callback) {
41133                         var socket = this.socket;
41134                         var rootScope = this.$rootScope;
41135                         socket.on(eventName, function () {
41136                             var args = arguments;
41137                             rootScope.$apply(function () {
41138                                 callback.apply(socket, args);
41139                             });
41140                         });
41141                     };
41142                     WebSocket.prototype.emit = function (eventName, data, callback) {
41143                         var socket = this.socket;
41144                         var rootScope = this.$rootScope;
41145                         this.socket.emit(eventName, data, function () {
41146                             var args = arguments;
41147                             rootScope.$apply(function () {
41148                                 if (callback)
41149                                     callback.apply(socket, args);
41150                             });
41151                         });
41152                     };
41153                     return WebSocket;
41154                 })();
41155                 services.WebSocket = WebSocket;
41156             })(services = app.services || (app.services = {}));
41157         })(app || (app = {}));
41158         var app;
41159         (function (app) {
41160             var directives;
41161             (function (directives) {
41162                 var Command = (function () {
41163                     function Command() {
41164                         this.restrict = 'E';
41165                         this.replace = true;
41166                         this.scope = true;
41167                         this.controller = 'commandController';
41168                         this.controllerAs = 'ctrl';
41169                         this.bindToController = {
41170                             index: '=',
41171                             name: '=',
41172                             remove: '&',
41173                             list: '='
41174                         };
41175                         this.templateUrl = 'templates/command.html';
41176                     }
41177                     Command.Factory = function () {
41178                         var directive = function () {
41179                             return new Command();
41180                         };
41181                         directive.$inject = [];
41182                         return directive;
41183                     };
41184                     return Command;
41185                 })();
41186                 directives.Command = Command;
41187                 var CommandController = (function () {
41188                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
41189                         this.APIEndPoint = APIEndPoint;
41190                         this.$scope = $scope;
41191                         this.MyModal = MyModal;
41192                         this.WebSocket = WebSocket;
41193                         this.$window = $window;
41194                         this.$rootScope = $rootScope;
41195                         var controller = this;
41196                         this.APIEndPoint
41197                             .getOptionControlFile(this.name)
41198                             .$promise
41199                             .then(function (result) {
41200                             controller.options = result.info;
41201                         });
41202                         this.APIEndPoint
41203                             .getDirectories()
41204                             .$promise
41205                             .then(function (result) {
41206                             controller.dirs = result.info;
41207                         });
41208                         this.heading = "[" + this.index + "]: dcdFilePrint";
41209                         this.isOpen = true;
41210                         this.$scope.$on('close', function () {
41211                             controller.isOpen = false;
41212                         });
41213                         function guid() {
41214                             function s4() {
41215                                 return Math.floor((1 + Math.random()) * 0x10000)
41216                                     .toString(16)
41217                                     .substring(1);
41218                             }
41219                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
41220                                 s4() + '-' + s4() + s4() + s4();
41221                         }
41222                         var uuid = guid();
41223                     }
41224                     CommandController.prototype.submit = function () {
41225                         var opt = [];
41226                         angular.forEach(this.options, function (option) {
41227                             var obj = {
41228                                 name: option.option,
41229                                 arguments: []
41230                             };
41231                             angular.forEach(option.arg, function (arg) {
41232                                 if (arg.input) {
41233                                     if (typeof arg.input === 'object') {
41234                                         obj.arguments.push(arg.input.name);
41235                                     }
41236                                     else {
41237                                         obj.arguments.push(arg.input);
41238                                     }
41239                                 }
41240                             });
41241                             if (obj.arguments.length > 0) {
41242                                 opt.push(obj);
41243                             }
41244                         });
41245                         var execObj = {
41246                             command: this.name,
41247                             workspace: this.workspace.fileId,
41248                             options: opt
41249                         };
41250                         this.APIEndPoint
41251                             .execute(JSON.stringify(execObj))
41252                             .then(function (result) {
41253                             console.log(result);
41254                         });
41255                     };
41256                     CommandController.prototype.removeMySelf = function (index) {
41257                         this.$scope.$destroy();
41258                         this.remove()(index, this.list);
41259                     };
41260                     CommandController.prototype.reloadFiles = function () {
41261                         var _this = this;
41262                         var fileId = this.workspace.fileId;
41263                         this.APIEndPoint
41264                             .getFiles(fileId)
41265                             .$promise
41266                             .then(function (result) {
41267                             var status = result.status;
41268                             if (status === 'success') {
41269                                 _this.files = result.info;
41270                             }
41271                             else {
41272                                 console.log(result.message);
41273                             }
41274                         });
41275                     };
41276                     CommandController.prototype.debug = function () {
41277                         console.log(this.$rootScope);
41278                         var div = angular.element(this.$window.document).find("div");
41279                         var consoleTag;
41280                         var parametersTag;
41281                         angular.forEach(div, function (v) {
41282                             if (v.className === "panel-body console") {
41283                                 consoleTag = v;
41284                             }
41285                             else if (v.className === "row parameters-console") {
41286                                 parametersTag = v;
41287                             }
41288                         });
41289                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
41290                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
41291                         consoleTag.style.height = consoleHeight;
41292                         consoleTag.style.width = consoleWidth;
41293                     };
41294                     CommandController.prototype.help = function () {
41295                         this.APIEndPoint
41296                             .help(this.name)
41297                             .then(function (result) {
41298                             console.log(result);
41299                         });
41300                     };
41301                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
41302                     return CommandController;
41303                 })();
41304                 directives.CommandController = CommandController;
41305             })(directives = app.directives || (app.directives = {}));
41306         })(app || (app = {}));
41307         var app;
41308         (function (app) {
41309             var directives;
41310             (function (directives) {
41311                 var HeaderMenu = (function () {
41312                     function HeaderMenu() {
41313                         this.restrict = 'E';
41314                         this.replace = true;
41315                         this.templateUrl = 'templates/header-menu.html';
41316                         this.controller = 'HeaderMenuController';
41317                         this.controllerAs = 'hmc';
41318                         this.scope = true;
41319                     }
41320                     HeaderMenu.Factory = function () {
41321                         var directive = function () {
41322                             return new HeaderMenu();
41323                         };
41324                         return directive;
41325                     };
41326                     return HeaderMenu;
41327                 })();
41328                 directives.HeaderMenu = HeaderMenu;
41329                 var HeaderMenuController = (function () {
41330                     function HeaderMenuController($state) {
41331                         this.$state = $state;
41332                         this.isExecution = this.$state.current.name === 'execution';
41333                         this.isWorkspace = this.$state.current.name === 'workspace';
41334                         this.isHistory = this.$state.current.name === 'history';
41335                     }
41336                     HeaderMenuController.prototype.transit = function (state) {
41337                         this.$state.go(state);
41338                     };
41339                     HeaderMenuController.$inject = ['$state'];
41340                     return HeaderMenuController;
41341                 })();
41342                 directives.HeaderMenuController = HeaderMenuController;
41343             })(directives = app.directives || (app.directives = {}));
41344         })(app || (app = {}));
41345         var app;
41346         (function (app) {
41347             var directives;
41348             (function (directives) {
41349                 var Option = (function () {
41350                     function Option() {
41351                         this.restrict = 'E';
41352                         this.replace = true;
41353                         this.controller = 'optionController';
41354                         this.bindToController = {
41355                             info: '=',
41356                             files: '='
41357                         };
41358                         this.scope = true;
41359                         this.templateUrl = 'templates/option.html';
41360                         this.controllerAs = 'ctrl';
41361                     }
41362                     Option.Factory = function () {
41363                         var directive = function () {
41364                             return new Option();
41365                         };
41366                         directive.$inject = [];
41367                         return directive;
41368                     };
41369                     return Option;
41370                 })();
41371                 directives.Option = Option;
41372                 var OptionController = (function () {
41373                     function OptionController() {
41374                         var controller = this;
41375                         angular.forEach(controller.info.arg, function (arg) {
41376                             if (arg.initialValue) {
41377                                 if (arg.formType === 'number') {
41378                                     arg.input = parseInt(arg.initialValue);
41379                                 }
41380                                 else {
41381                                     arg.input = arg.initialValue;
41382                                 }
41383                             }
41384                         });
41385                     }
41386                     OptionController.$inject = [];
41387                     return OptionController;
41388                 })();
41389                 directives.OptionController = OptionController;
41390             })(directives = app.directives || (app.directives = {}));
41391         })(app || (app = {}));
41392         var app;
41393         (function (app) {
41394             var directives;
41395             (function (directives) {
41396                 var Directory = (function () {
41397                     function Directory() {
41398                         this.restrict = 'E';
41399                         this.replace = true;
41400                         this.controller = 'directoryController';
41401                         this.controllerAs = 'ctrl';
41402                         this.bindToController = {
41403                             info: '=',
41404                             add: '&',
41405                             list: '=',
41406                             files: '='
41407                         };
41408                         this.templateUrl = 'templates/directory.html';
41409                     }
41410                     Directory.Factory = function () {
41411                         var directive = function () {
41412                             return new Directory();
41413                         };
41414                         return directive;
41415                     };
41416                     return Directory;
41417                 })();
41418                 directives.Directory = Directory;
41419                 var DirectoryController = (function () {
41420                     function DirectoryController(APIEndPoint, $scope) {
41421                         this.APIEndPoint = APIEndPoint;
41422                         this.$scope = $scope;
41423                         var controller = this;
41424                         this.APIEndPoint
41425                             .getFiles(this.info.fileId)
41426                             .$promise
41427                             .then(function (result) {
41428                             if (result.status === 'success') {
41429                                 controller.files = result.info;
41430                                 angular.forEach(result.info, function (file) {
41431                                     if (file.fileType === '0') {
41432                                         var o = file;
41433                                         if (controller.info.path === '/') {
41434                                             o.path = '/' + file.name;
41435                                         }
41436                                         else {
41437                                             o.path = controller.info.path + '/' + file.name;
41438                                         }
41439                                         controller.add()(o, controller.list);
41440                                     }
41441                                 });
41442                             }
41443                             ;
41444                         });
41445                     }
41446                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
41447                     return DirectoryController;
41448                 })();
41449                 directives.DirectoryController = DirectoryController;
41450             })(directives = app.directives || (app.directives = {}));
41451         })(app || (app = {}));
41452         var app;
41453         (function (app) {
41454             var controllers;
41455             (function (controllers) {
41456                 var Execution = (function () {
41457                     function Execution(MyModal, $scope) {
41458                         this.MyModal = MyModal;
41459                         this.$scope = $scope;
41460                         this.commandInfoList = [];
41461                     }
41462                     ;
41463                     Execution.prototype.add = function () {
41464                         this.$scope.$broadcast('close');
41465                         var commandInfoList = this.commandInfoList;
41466                         var commandInstance = this.MyModal.selectCommand();
41467                         commandInstance
41468                             .result
41469                             .then(function (command) {
41470                             commandInfoList.push(new app.declares.CommandInfo(command));
41471                         });
41472                     };
41473                     Execution.prototype.open = function () {
41474                         var result = this.MyModal.open('SelectCommand');
41475                         console.log(result);
41476                     };
41477                     Execution.prototype.remove = function (index, list) {
41478                         list.splice(index, 1);
41479                     };
41480                     Execution.prototype.close = function () {
41481                         console.log("close");
41482                     };
41483                     Execution.$inject = ['MyModal', '$scope'];
41484                     return Execution;
41485                 })();
41486                 controllers.Execution = Execution;
41487             })(controllers = app.controllers || (app.controllers = {}));
41488         })(app || (app = {}));
41489         var app;
41490         (function (app) {
41491             var controllers;
41492             (function (controllers) {
41493                 var Workspace = (function () {
41494                     function Workspace($scope, APIEndPoint, MyModal) {
41495                         this.$scope = $scope;
41496                         this.APIEndPoint = APIEndPoint;
41497                         this.MyModal = MyModal;
41498                         this.directoryList = [];
41499                         var controller = this;
41500                         var directoryList = this.directoryList;
41501                         var o = {
41502                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
41503                             name: '',
41504                             parentId: '',
41505                             fileType: '',
41506                             createdAt: '',
41507                             updatedAt: '',
41508                             path: '/'
41509                         };
41510                         directoryList.push(o);
41511                     }
41512                     Workspace.prototype.addDirectory = function (info, directoryList) {
41513                         directoryList.push(info);
41514                     };
41515                     Workspace.prototype.debug = function () {
41516                         this.MyModal.preview();
41517                     };
41518                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
41519                     return Workspace;
41520                 })();
41521                 controllers.Workspace = Workspace;
41522             })(controllers = app.controllers || (app.controllers = {}));
41523         })(app || (app = {}));
41524         var app;
41525         (function (app) {
41526             var controllers;
41527             (function (controllers) {
41528                 var History = (function () {
41529                     function History($scope) {
41530                         this.page = "History";
41531                     }
41532                     History.$inject = ['$scope'];
41533                     return History;
41534                 })();
41535                 controllers.History = History;
41536             })(controllers = app.controllers || (app.controllers = {}));
41537         })(app || (app = {}));
41538         var app;
41539         (function (app) {
41540             var controllers;
41541             (function (controllers) {
41542                 var SelectCommand = (function () {
41543                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
41544                         this.APIEndPoint = APIEndPoint;
41545                         this.$modalInstance = $modalInstance;
41546                         var controller = this;
41547                         this.APIEndPoint
41548                             .getTags()
41549                             .$promise.then(function (result) {
41550                             controller.tags = result.info;
41551                         });
41552                         this.APIEndPoint
41553                             .getCommands()
41554                             .$promise.then(function (result) {
41555                             controller.commands = result.info;
41556                         });
41557                         this.currentTag = 'all';
41558                     }
41559                     SelectCommand.prototype.changeTag = function (tag) {
41560                         this.currentTag = tag;
41561                     };
41562                     SelectCommand.prototype.selectCommand = function (command) {
41563                         this.$modalInstance.close(command);
41564                     };
41565                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
41566                     return SelectCommand;
41567                 })();
41568                 controllers.SelectCommand = SelectCommand;
41569             })(controllers = app.controllers || (app.controllers = {}));
41570         })(app || (app = {}));
41571         var app;
41572         (function (app) {
41573             var controllers;
41574             (function (controllers) {
41575                 var Preview = (function () {
41576                     function Preview($scope, APIEndPoint, $modalInstance) {
41577                         this.APIEndPoint = APIEndPoint;
41578                         this.$modalInstance = $modalInstance;
41579                         var controller = this;
41580                         console.log('preview');
41581                     }
41582                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
41583                     return Preview;
41584                 })();
41585                 controllers.Preview = Preview;
41586             })(controllers = app.controllers || (app.controllers = {}));
41587         })(app || (app = {}));
41588         var filters;
41589         (function (filters) {
41590             function Tag() {
41591                 return function (commands, tag) {
41592                     var result = [];
41593                     angular.forEach(commands, function (command) {
41594                         var flag = false;
41595                         angular.forEach(command.tags, function (value) {
41596                             if (tag === value)
41597                                 flag = true;
41598                         });
41599                         if (flag)
41600                             result.push(command);
41601                     });
41602                     return result;
41603                 };
41604             }
41605             filters.Tag = Tag;
41606         })(filters || (filters = {}));
41607         var app;
41608         (function (app) {
41609             'use strict';
41610             var appName = 'zephyr';
41611             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
41612             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
41613                 $urlRouterProvider.otherwise('/execution');
41614                 $locationProvider.html5Mode({
41615                     enabled: true,
41616                     requireBase: false
41617                 });
41618                 $stateProvider
41619                     .state('execution', {
41620                     url: '/execution',
41621                     templateUrl: 'templates/execution.html',
41622                     controller: 'executionController',
41623                     controllerAs: 'c'
41624                 })
41625                     .state('workspace', {
41626                     url: '/workspace',
41627                     templateUrl: 'templates/workspace.html',
41628                     controller: 'workspaceController',
41629                     controllerAs: 'c'
41630                 })
41631                     .state('history', {
41632                     url: '/history',
41633                     templateUrl: 'templates/history.html',
41634                     controller: 'historyController',
41635                     controllerAs: 'c'
41636                 });
41637             });
41638             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
41639             app.zephyr.service('MyModal', app.services.MyModal);
41640             app.zephyr.service('WebSocket', app.services.WebSocket);
41641             app.zephyr.filter('Tag', filters.Tag);
41642             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
41643             app.zephyr.controller('previewController', app.controllers.Preview);
41644             app.zephyr.controller('executionController', app.controllers.Execution);
41645             app.zephyr.controller('workspaceController', app.controllers.Workspace);
41646             app.zephyr.controller('historyController', app.controllers.History);
41647             app.zephyr.controller('commandController', app.directives.CommandController);
41648             app.zephyr.controller('optionController', app.directives.OptionController);
41649             app.zephyr.controller('directoryController', app.directives.DirectoryController);
41650             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
41651             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
41652             app.zephyr.directive('command', app.directives.Command.Factory());
41653             app.zephyr.directive('option', app.directives.Option.Factory());
41654             app.zephyr.directive('directory', app.directives.Directory.Factory());
41655         })(app || (app = {}));
41656
41657
41658 /***/ },
41659 /* 9 */
41660 /***/ function(module, exports) {
41661
41662         var app;
41663         (function (app) {
41664             var declares;
41665             (function (declares) {
41666                 var CommandInfo = (function () {
41667                     function CommandInfo(name) {
41668                         this.name = name;
41669                     }
41670                     return CommandInfo;
41671                 })();
41672                 declares.CommandInfo = CommandInfo;
41673             })(declares = app.declares || (app.declares = {}));
41674         })(app || (app = {}));
41675         var app;
41676         (function (app) {
41677             var services;
41678             (function (services) {
41679                 var APIEndPoint = (function () {
41680                     function APIEndPoint($resource, $http) {
41681                         this.$resource = $resource;
41682                         this.$http = $http;
41683                     }
41684                     APIEndPoint.prototype.resource = function (endPoint, data) {
41685                         var customAction = {
41686                             method: 'GET',
41687                             isArray: false
41688                         };
41689                         var execute = {
41690                             method: 'POST',
41691                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
41692                         };
41693                         return this.$resource(endPoint, {}, { execute: execute });
41694                     };
41695                     APIEndPoint.prototype.getOptionControlFile = function (command) {
41696                         var endPoint = '/api/v1/optionControlFile/' + command;
41697                         return this.resource(endPoint, {}).get();
41698                     };
41699                     APIEndPoint.prototype.getFiles = function (fileId) {
41700                         var endPoint = '/api/v1/workspace';
41701                         if (fileId) {
41702                             endPoint += '/' + fileId;
41703                         }
41704                         return this.resource(endPoint, {}).get();
41705                     };
41706                     APIEndPoint.prototype.getDirectories = function () {
41707                         var endPoint = '/api/v1/all/workspace/directory';
41708                         return this.resource(endPoint, {}).get();
41709                     };
41710                     APIEndPoint.prototype.getTags = function () {
41711                         var endPoint = '/api/v1/tagList';
41712                         return this.resource(endPoint, {}).get();
41713                     };
41714                     APIEndPoint.prototype.getCommands = function () {
41715                         var endPoint = '/api/v1/commandList';
41716                         return this.resource(endPoint, {}).get();
41717                     };
41718                     APIEndPoint.prototype.execute = function (data) {
41719                         var endPoint = '/api/v1/execution';
41720                         var fd = new FormData();
41721                         fd.append('data', data);
41722                         return this.$http.post(endPoint, fd, {
41723                             headers: { 'Content-Type': undefined },
41724                             transformRequest: angular.identity
41725                         });
41726                     };
41727                     APIEndPoint.prototype.debug = function () {
41728                         var endPoint = '/api/v1/debug';
41729                         return this.$http.get(endPoint);
41730                     };
41731                     APIEndPoint.prototype.help = function (command) {
41732                         var endPoint = '/api/v1/help/' + command;
41733                         return this.$http.get(endPoint);
41734                     };
41735                     return APIEndPoint;
41736                 })();
41737                 services.APIEndPoint = APIEndPoint;
41738             })(services = app.services || (app.services = {}));
41739         })(app || (app = {}));
41740         var app;
41741         (function (app) {
41742             var services;
41743             (function (services) {
41744                 var MyModal = (function () {
41745                     function MyModal($uibModal) {
41746                         this.$uibModal = $uibModal;
41747                         this.modalOption = {
41748                             backdrop: true,
41749                             controller: null,
41750                             templateUrl: null,
41751                             size: null
41752                         };
41753                     }
41754                     MyModal.prototype.open = function (modalName) {
41755                         if (modalName === 'SelectCommand') {
41756                             this.modalOption.templateUrl = 'templates/select-command.html';
41757                             this.modalOption.size = 'lg';
41758                         }
41759                         return this.$uibModal.open(this.modalOption);
41760                     };
41761                     MyModal.prototype.selectCommand = function () {
41762                         this.modalOption.templateUrl = 'templates/select-command.html';
41763                         this.modalOption.controller = 'selectCommandController';
41764                         this.modalOption.controllerAs = 'c';
41765                         this.modalOption.size = 'lg';
41766                         return this.$uibModal.open(this.modalOption);
41767                     };
41768                     MyModal.prototype.preview = function () {
41769                         this.modalOption.templateUrl = 'templates/preview.html';
41770                         this.modalOption.controller = 'previewController';
41771                         this.modalOption.controllerAs = 'c';
41772                         this.modalOption.size = 'lg';
41773                         return this.$uibModal.open(this.modalOption);
41774                     };
41775                     MyModal.$inject = ['$uibModal'];
41776                     return MyModal;
41777                 })();
41778                 services.MyModal = MyModal;
41779             })(services = app.services || (app.services = {}));
41780         })(app || (app = {}));
41781         var app;
41782         (function (app) {
41783             var services;
41784             (function (services) {
41785                 var WebSocket = (function () {
41786                     function WebSocket($rootScope) {
41787                         this.$rootScope = $rootScope;
41788                         this.socket = io.connect();
41789                     }
41790                     WebSocket.prototype.on = function (eventName, callback) {
41791                         var socket = this.socket;
41792                         var rootScope = this.$rootScope;
41793                         socket.on(eventName, function () {
41794                             var args = arguments;
41795                             rootScope.$apply(function () {
41796                                 callback.apply(socket, args);
41797                             });
41798                         });
41799                     };
41800                     WebSocket.prototype.emit = function (eventName, data, callback) {
41801                         var socket = this.socket;
41802                         var rootScope = this.$rootScope;
41803                         this.socket.emit(eventName, data, function () {
41804                             var args = arguments;
41805                             rootScope.$apply(function () {
41806                                 if (callback)
41807                                     callback.apply(socket, args);
41808                             });
41809                         });
41810                     };
41811                     return WebSocket;
41812                 })();
41813                 services.WebSocket = WebSocket;
41814             })(services = app.services || (app.services = {}));
41815         })(app || (app = {}));
41816         var app;
41817         (function (app) {
41818             var directives;
41819             (function (directives) {
41820                 var Command = (function () {
41821                     function Command() {
41822                         this.restrict = 'E';
41823                         this.replace = true;
41824                         this.scope = true;
41825                         this.controller = 'commandController';
41826                         this.controllerAs = 'ctrl';
41827                         this.bindToController = {
41828                             index: '=',
41829                             name: '=',
41830                             remove: '&',
41831                             list: '='
41832                         };
41833                         this.templateUrl = 'templates/command.html';
41834                     }
41835                     Command.Factory = function () {
41836                         var directive = function () {
41837                             return new Command();
41838                         };
41839                         directive.$inject = [];
41840                         return directive;
41841                     };
41842                     return Command;
41843                 })();
41844                 directives.Command = Command;
41845                 var CommandController = (function () {
41846                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
41847                         this.APIEndPoint = APIEndPoint;
41848                         this.$scope = $scope;
41849                         this.MyModal = MyModal;
41850                         this.WebSocket = WebSocket;
41851                         this.$window = $window;
41852                         this.$rootScope = $rootScope;
41853                         var controller = this;
41854                         this.APIEndPoint
41855                             .getOptionControlFile(this.name)
41856                             .$promise
41857                             .then(function (result) {
41858                             controller.options = result.info;
41859                         });
41860                         this.APIEndPoint
41861                             .getDirectories()
41862                             .$promise
41863                             .then(function (result) {
41864                             controller.dirs = result.info;
41865                         });
41866                         this.heading = "[" + this.index + "]: dcdFilePrint";
41867                         this.isOpen = true;
41868                         this.$scope.$on('close', function () {
41869                             controller.isOpen = false;
41870                         });
41871                         function guid() {
41872                             function s4() {
41873                                 return Math.floor((1 + Math.random()) * 0x10000)
41874                                     .toString(16)
41875                                     .substring(1);
41876                             }
41877                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
41878                                 s4() + '-' + s4() + s4() + s4();
41879                         }
41880                         var uuid = guid();
41881                     }
41882                     CommandController.prototype.submit = function () {
41883                         var opt = [];
41884                         angular.forEach(this.options, function (option) {
41885                             var obj = {
41886                                 name: option.option,
41887                                 arguments: []
41888                             };
41889                             angular.forEach(option.arg, function (arg) {
41890                                 if (arg.input) {
41891                                     if (typeof arg.input === 'object') {
41892                                         obj.arguments.push(arg.input.name);
41893                                     }
41894                                     else {
41895                                         obj.arguments.push(arg.input);
41896                                     }
41897                                 }
41898                             });
41899                             if (obj.arguments.length > 0) {
41900                                 opt.push(obj);
41901                             }
41902                         });
41903                         var execObj = {
41904                             command: this.name,
41905                             workspace: this.workspace.fileId,
41906                             options: opt
41907                         };
41908                         this.APIEndPoint
41909                             .execute(JSON.stringify(execObj))
41910                             .then(function (result) {
41911                             console.log(result);
41912                         });
41913                     };
41914                     CommandController.prototype.removeMySelf = function (index) {
41915                         this.$scope.$destroy();
41916                         this.remove()(index, this.list);
41917                     };
41918                     CommandController.prototype.reloadFiles = function () {
41919                         var _this = this;
41920                         var fileId = this.workspace.fileId;
41921                         this.APIEndPoint
41922                             .getFiles(fileId)
41923                             .$promise
41924                             .then(function (result) {
41925                             var status = result.status;
41926                             if (status === 'success') {
41927                                 _this.files = result.info;
41928                             }
41929                             else {
41930                                 console.log(result.message);
41931                             }
41932                         });
41933                     };
41934                     CommandController.prototype.debug = function () {
41935                         console.log(this.$rootScope);
41936                         var div = angular.element(this.$window.document).find("div");
41937                         var consoleTag;
41938                         var parametersTag;
41939                         angular.forEach(div, function (v) {
41940                             if (v.className === "panel-body console") {
41941                                 consoleTag = v;
41942                             }
41943                             else if (v.className === "row parameters-console") {
41944                                 parametersTag = v;
41945                             }
41946                         });
41947                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
41948                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
41949                         consoleTag.style.height = consoleHeight;
41950                         consoleTag.style.width = consoleWidth;
41951                     };
41952                     CommandController.prototype.help = function () {
41953                         this.APIEndPoint
41954                             .help(this.name)
41955                             .then(function (result) {
41956                             console.log(result);
41957                         });
41958                     };
41959                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
41960                     return CommandController;
41961                 })();
41962                 directives.CommandController = CommandController;
41963             })(directives = app.directives || (app.directives = {}));
41964         })(app || (app = {}));
41965         var app;
41966         (function (app) {
41967             var directives;
41968             (function (directives) {
41969                 var HeaderMenu = (function () {
41970                     function HeaderMenu() {
41971                         this.restrict = 'E';
41972                         this.replace = true;
41973                         this.templateUrl = 'templates/header-menu.html';
41974                         this.controller = 'HeaderMenuController';
41975                         this.controllerAs = 'hmc';
41976                         this.scope = true;
41977                     }
41978                     HeaderMenu.Factory = function () {
41979                         var directive = function () {
41980                             return new HeaderMenu();
41981                         };
41982                         return directive;
41983                     };
41984                     return HeaderMenu;
41985                 })();
41986                 directives.HeaderMenu = HeaderMenu;
41987                 var HeaderMenuController = (function () {
41988                     function HeaderMenuController($state) {
41989                         this.$state = $state;
41990                         this.isExecution = this.$state.current.name === 'execution';
41991                         this.isWorkspace = this.$state.current.name === 'workspace';
41992                         this.isHistory = this.$state.current.name === 'history';
41993                     }
41994                     HeaderMenuController.prototype.transit = function (state) {
41995                         this.$state.go(state);
41996                     };
41997                     HeaderMenuController.$inject = ['$state'];
41998                     return HeaderMenuController;
41999                 })();
42000                 directives.HeaderMenuController = HeaderMenuController;
42001             })(directives = app.directives || (app.directives = {}));
42002         })(app || (app = {}));
42003         var app;
42004         (function (app) {
42005             var directives;
42006             (function (directives) {
42007                 var Option = (function () {
42008                     function Option() {
42009                         this.restrict = 'E';
42010                         this.replace = true;
42011                         this.controller = 'optionController';
42012                         this.bindToController = {
42013                             info: '=',
42014                             files: '='
42015                         };
42016                         this.scope = true;
42017                         this.templateUrl = 'templates/option.html';
42018                         this.controllerAs = 'ctrl';
42019                     }
42020                     Option.Factory = function () {
42021                         var directive = function () {
42022                             return new Option();
42023                         };
42024                         directive.$inject = [];
42025                         return directive;
42026                     };
42027                     return Option;
42028                 })();
42029                 directives.Option = Option;
42030                 var OptionController = (function () {
42031                     function OptionController() {
42032                         var controller = this;
42033                         angular.forEach(controller.info.arg, function (arg) {
42034                             if (arg.initialValue) {
42035                                 if (arg.formType === 'number') {
42036                                     arg.input = parseInt(arg.initialValue);
42037                                 }
42038                                 else {
42039                                     arg.input = arg.initialValue;
42040                                 }
42041                             }
42042                         });
42043                     }
42044                     OptionController.$inject = [];
42045                     return OptionController;
42046                 })();
42047                 directives.OptionController = OptionController;
42048             })(directives = app.directives || (app.directives = {}));
42049         })(app || (app = {}));
42050         var app;
42051         (function (app) {
42052             var directives;
42053             (function (directives) {
42054                 var Directory = (function () {
42055                     function Directory() {
42056                         this.restrict = 'E';
42057                         this.replace = true;
42058                         this.controller = 'directoryController';
42059                         this.controllerAs = 'ctrl';
42060                         this.bindToController = {
42061                             info: '=',
42062                             add: '&',
42063                             list: '=',
42064                             files: '='
42065                         };
42066                         this.templateUrl = 'templates/directory.html';
42067                     }
42068                     Directory.Factory = function () {
42069                         var directive = function () {
42070                             return new Directory();
42071                         };
42072                         return directive;
42073                     };
42074                     return Directory;
42075                 })();
42076                 directives.Directory = Directory;
42077                 var DirectoryController = (function () {
42078                     function DirectoryController(APIEndPoint, $scope) {
42079                         this.APIEndPoint = APIEndPoint;
42080                         this.$scope = $scope;
42081                         var controller = this;
42082                         this.APIEndPoint
42083                             .getFiles(this.info.fileId)
42084                             .$promise
42085                             .then(function (result) {
42086                             if (result.status === 'success') {
42087                                 controller.files = result.info;
42088                                 angular.forEach(result.info, function (file) {
42089                                     if (file.fileType === '0') {
42090                                         var o = file;
42091                                         if (controller.info.path === '/') {
42092                                             o.path = '/' + file.name;
42093                                         }
42094                                         else {
42095                                             o.path = controller.info.path + '/' + file.name;
42096                                         }
42097                                         controller.add()(o, controller.list);
42098                                     }
42099                                 });
42100                             }
42101                             ;
42102                         });
42103                     }
42104                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
42105                     return DirectoryController;
42106                 })();
42107                 directives.DirectoryController = DirectoryController;
42108             })(directives = app.directives || (app.directives = {}));
42109         })(app || (app = {}));
42110         var app;
42111         (function (app) {
42112             var controllers;
42113             (function (controllers) {
42114                 var Execution = (function () {
42115                     function Execution(MyModal, $scope) {
42116                         this.MyModal = MyModal;
42117                         this.$scope = $scope;
42118                         this.commandInfoList = [];
42119                     }
42120                     ;
42121                     Execution.prototype.add = function () {
42122                         this.$scope.$broadcast('close');
42123                         var commandInfoList = this.commandInfoList;
42124                         var commandInstance = this.MyModal.selectCommand();
42125                         commandInstance
42126                             .result
42127                             .then(function (command) {
42128                             commandInfoList.push(new app.declares.CommandInfo(command));
42129                         });
42130                     };
42131                     Execution.prototype.open = function () {
42132                         var result = this.MyModal.open('SelectCommand');
42133                         console.log(result);
42134                     };
42135                     Execution.prototype.remove = function (index, list) {
42136                         list.splice(index, 1);
42137                     };
42138                     Execution.prototype.close = function () {
42139                         console.log("close");
42140                     };
42141                     Execution.$inject = ['MyModal', '$scope'];
42142                     return Execution;
42143                 })();
42144                 controllers.Execution = Execution;
42145             })(controllers = app.controllers || (app.controllers = {}));
42146         })(app || (app = {}));
42147         var app;
42148         (function (app) {
42149             var controllers;
42150             (function (controllers) {
42151                 var Workspace = (function () {
42152                     function Workspace($scope, APIEndPoint, MyModal) {
42153                         this.$scope = $scope;
42154                         this.APIEndPoint = APIEndPoint;
42155                         this.MyModal = MyModal;
42156                         this.directoryList = [];
42157                         var controller = this;
42158                         var directoryList = this.directoryList;
42159                         var o = {
42160                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
42161                             name: '',
42162                             parentId: '',
42163                             fileType: '',
42164                             createdAt: '',
42165                             updatedAt: '',
42166                             path: '/'
42167                         };
42168                         directoryList.push(o);
42169                     }
42170                     Workspace.prototype.addDirectory = function (info, directoryList) {
42171                         directoryList.push(info);
42172                     };
42173                     Workspace.prototype.debug = function () {
42174                         this.MyModal.preview();
42175                     };
42176                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
42177                     return Workspace;
42178                 })();
42179                 controllers.Workspace = Workspace;
42180             })(controllers = app.controllers || (app.controllers = {}));
42181         })(app || (app = {}));
42182         var app;
42183         (function (app) {
42184             var controllers;
42185             (function (controllers) {
42186                 var History = (function () {
42187                     function History($scope) {
42188                         this.page = "History";
42189                     }
42190                     History.$inject = ['$scope'];
42191                     return History;
42192                 })();
42193                 controllers.History = History;
42194             })(controllers = app.controllers || (app.controllers = {}));
42195         })(app || (app = {}));
42196         var app;
42197         (function (app) {
42198             var controllers;
42199             (function (controllers) {
42200                 var SelectCommand = (function () {
42201                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
42202                         this.APIEndPoint = APIEndPoint;
42203                         this.$modalInstance = $modalInstance;
42204                         var controller = this;
42205                         this.APIEndPoint
42206                             .getTags()
42207                             .$promise.then(function (result) {
42208                             controller.tags = result.info;
42209                         });
42210                         this.APIEndPoint
42211                             .getCommands()
42212                             .$promise.then(function (result) {
42213                             controller.commands = result.info;
42214                         });
42215                         this.currentTag = 'all';
42216                     }
42217                     SelectCommand.prototype.changeTag = function (tag) {
42218                         this.currentTag = tag;
42219                     };
42220                     SelectCommand.prototype.selectCommand = function (command) {
42221                         this.$modalInstance.close(command);
42222                     };
42223                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42224                     return SelectCommand;
42225                 })();
42226                 controllers.SelectCommand = SelectCommand;
42227             })(controllers = app.controllers || (app.controllers = {}));
42228         })(app || (app = {}));
42229         var app;
42230         (function (app) {
42231             var controllers;
42232             (function (controllers) {
42233                 var Preview = (function () {
42234                     function Preview($scope, APIEndPoint, $modalInstance) {
42235                         this.APIEndPoint = APIEndPoint;
42236                         this.$modalInstance = $modalInstance;
42237                         var controller = this;
42238                         console.log('preview');
42239                     }
42240                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42241                     return Preview;
42242                 })();
42243                 controllers.Preview = Preview;
42244             })(controllers = app.controllers || (app.controllers = {}));
42245         })(app || (app = {}));
42246         var filters;
42247         (function (filters) {
42248             function Tag() {
42249                 return function (commands, tag) {
42250                     var result = [];
42251                     angular.forEach(commands, function (command) {
42252                         var flag = false;
42253                         angular.forEach(command.tags, function (value) {
42254                             if (tag === value)
42255                                 flag = true;
42256                         });
42257                         if (flag)
42258                             result.push(command);
42259                     });
42260                     return result;
42261                 };
42262             }
42263             filters.Tag = Tag;
42264         })(filters || (filters = {}));
42265         var app;
42266         (function (app) {
42267             'use strict';
42268             var appName = 'zephyr';
42269             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
42270             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
42271                 $urlRouterProvider.otherwise('/execution');
42272                 $locationProvider.html5Mode({
42273                     enabled: true,
42274                     requireBase: false
42275                 });
42276                 $stateProvider
42277                     .state('execution', {
42278                     url: '/execution',
42279                     templateUrl: 'templates/execution.html',
42280                     controller: 'executionController',
42281                     controllerAs: 'c'
42282                 })
42283                     .state('workspace', {
42284                     url: '/workspace',
42285                     templateUrl: 'templates/workspace.html',
42286                     controller: 'workspaceController',
42287                     controllerAs: 'c'
42288                 })
42289                     .state('history', {
42290                     url: '/history',
42291                     templateUrl: 'templates/history.html',
42292                     controller: 'historyController',
42293                     controllerAs: 'c'
42294                 });
42295             });
42296             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
42297             app.zephyr.service('MyModal', app.services.MyModal);
42298             app.zephyr.service('WebSocket', app.services.WebSocket);
42299             app.zephyr.filter('Tag', filters.Tag);
42300             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
42301             app.zephyr.controller('previewController', app.controllers.Preview);
42302             app.zephyr.controller('executionController', app.controllers.Execution);
42303             app.zephyr.controller('workspaceController', app.controllers.Workspace);
42304             app.zephyr.controller('historyController', app.controllers.History);
42305             app.zephyr.controller('commandController', app.directives.CommandController);
42306             app.zephyr.controller('optionController', app.directives.OptionController);
42307             app.zephyr.controller('directoryController', app.directives.DirectoryController);
42308             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
42309             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
42310             app.zephyr.directive('command', app.directives.Command.Factory());
42311             app.zephyr.directive('option', app.directives.Option.Factory());
42312             app.zephyr.directive('directory', app.directives.Directory.Factory());
42313         })(app || (app = {}));
42314
42315
42316 /***/ },
42317 /* 10 */
42318 /***/ function(module, exports) {
42319
42320         var app;
42321         (function (app) {
42322             var declares;
42323             (function (declares) {
42324                 var CommandInfo = (function () {
42325                     function CommandInfo(name) {
42326                         this.name = name;
42327                     }
42328                     return CommandInfo;
42329                 })();
42330                 declares.CommandInfo = CommandInfo;
42331             })(declares = app.declares || (app.declares = {}));
42332         })(app || (app = {}));
42333         var app;
42334         (function (app) {
42335             var services;
42336             (function (services) {
42337                 var APIEndPoint = (function () {
42338                     function APIEndPoint($resource, $http) {
42339                         this.$resource = $resource;
42340                         this.$http = $http;
42341                     }
42342                     APIEndPoint.prototype.resource = function (endPoint, data) {
42343                         var customAction = {
42344                             method: 'GET',
42345                             isArray: false
42346                         };
42347                         var execute = {
42348                             method: 'POST',
42349                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
42350                         };
42351                         return this.$resource(endPoint, {}, { execute: execute });
42352                     };
42353                     APIEndPoint.prototype.getOptionControlFile = function (command) {
42354                         var endPoint = '/api/v1/optionControlFile/' + command;
42355                         return this.resource(endPoint, {}).get();
42356                     };
42357                     APIEndPoint.prototype.getFiles = function (fileId) {
42358                         var endPoint = '/api/v1/workspace';
42359                         if (fileId) {
42360                             endPoint += '/' + fileId;
42361                         }
42362                         return this.resource(endPoint, {}).get();
42363                     };
42364                     APIEndPoint.prototype.getDirectories = function () {
42365                         var endPoint = '/api/v1/all/workspace/directory';
42366                         return this.resource(endPoint, {}).get();
42367                     };
42368                     APIEndPoint.prototype.getTags = function () {
42369                         var endPoint = '/api/v1/tagList';
42370                         return this.resource(endPoint, {}).get();
42371                     };
42372                     APIEndPoint.prototype.getCommands = function () {
42373                         var endPoint = '/api/v1/commandList';
42374                         return this.resource(endPoint, {}).get();
42375                     };
42376                     APIEndPoint.prototype.execute = function (data) {
42377                         var endPoint = '/api/v1/execution';
42378                         var fd = new FormData();
42379                         fd.append('data', data);
42380                         return this.$http.post(endPoint, fd, {
42381                             headers: { 'Content-Type': undefined },
42382                             transformRequest: angular.identity
42383                         });
42384                     };
42385                     APIEndPoint.prototype.debug = function () {
42386                         var endPoint = '/api/v1/debug';
42387                         return this.$http.get(endPoint);
42388                     };
42389                     APIEndPoint.prototype.help = function (command) {
42390                         var endPoint = '/api/v1/help/' + command;
42391                         return this.$http.get(endPoint);
42392                     };
42393                     return APIEndPoint;
42394                 })();
42395                 services.APIEndPoint = APIEndPoint;
42396             })(services = app.services || (app.services = {}));
42397         })(app || (app = {}));
42398         var app;
42399         (function (app) {
42400             var services;
42401             (function (services) {
42402                 var MyModal = (function () {
42403                     function MyModal($uibModal) {
42404                         this.$uibModal = $uibModal;
42405                         this.modalOption = {
42406                             backdrop: true,
42407                             controller: null,
42408                             templateUrl: null,
42409                             size: null
42410                         };
42411                     }
42412                     MyModal.prototype.open = function (modalName) {
42413                         if (modalName === 'SelectCommand') {
42414                             this.modalOption.templateUrl = 'templates/select-command.html';
42415                             this.modalOption.size = 'lg';
42416                         }
42417                         return this.$uibModal.open(this.modalOption);
42418                     };
42419                     MyModal.prototype.selectCommand = function () {
42420                         this.modalOption.templateUrl = 'templates/select-command.html';
42421                         this.modalOption.controller = 'selectCommandController';
42422                         this.modalOption.controllerAs = 'c';
42423                         this.modalOption.size = 'lg';
42424                         return this.$uibModal.open(this.modalOption);
42425                     };
42426                     MyModal.prototype.preview = function () {
42427                         this.modalOption.templateUrl = 'templates/preview.html';
42428                         this.modalOption.controller = 'previewController';
42429                         this.modalOption.controllerAs = 'c';
42430                         this.modalOption.size = 'lg';
42431                         return this.$uibModal.open(this.modalOption);
42432                     };
42433                     MyModal.$inject = ['$uibModal'];
42434                     return MyModal;
42435                 })();
42436                 services.MyModal = MyModal;
42437             })(services = app.services || (app.services = {}));
42438         })(app || (app = {}));
42439         var app;
42440         (function (app) {
42441             var services;
42442             (function (services) {
42443                 var WebSocket = (function () {
42444                     function WebSocket($rootScope) {
42445                         this.$rootScope = $rootScope;
42446                         this.socket = io.connect();
42447                     }
42448                     WebSocket.prototype.on = function (eventName, callback) {
42449                         var socket = this.socket;
42450                         var rootScope = this.$rootScope;
42451                         socket.on(eventName, function () {
42452                             var args = arguments;
42453                             rootScope.$apply(function () {
42454                                 callback.apply(socket, args);
42455                             });
42456                         });
42457                     };
42458                     WebSocket.prototype.emit = function (eventName, data, callback) {
42459                         var socket = this.socket;
42460                         var rootScope = this.$rootScope;
42461                         this.socket.emit(eventName, data, function () {
42462                             var args = arguments;
42463                             rootScope.$apply(function () {
42464                                 if (callback)
42465                                     callback.apply(socket, args);
42466                             });
42467                         });
42468                     };
42469                     return WebSocket;
42470                 })();
42471                 services.WebSocket = WebSocket;
42472             })(services = app.services || (app.services = {}));
42473         })(app || (app = {}));
42474         var app;
42475         (function (app) {
42476             var directives;
42477             (function (directives) {
42478                 var Command = (function () {
42479                     function Command() {
42480                         this.restrict = 'E';
42481                         this.replace = true;
42482                         this.scope = true;
42483                         this.controller = 'commandController';
42484                         this.controllerAs = 'ctrl';
42485                         this.bindToController = {
42486                             index: '=',
42487                             name: '=',
42488                             remove: '&',
42489                             list: '='
42490                         };
42491                         this.templateUrl = 'templates/command.html';
42492                     }
42493                     Command.Factory = function () {
42494                         var directive = function () {
42495                             return new Command();
42496                         };
42497                         directive.$inject = [];
42498                         return directive;
42499                     };
42500                     return Command;
42501                 })();
42502                 directives.Command = Command;
42503                 var CommandController = (function () {
42504                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
42505                         this.APIEndPoint = APIEndPoint;
42506                         this.$scope = $scope;
42507                         this.MyModal = MyModal;
42508                         this.WebSocket = WebSocket;
42509                         this.$window = $window;
42510                         this.$rootScope = $rootScope;
42511                         var controller = this;
42512                         this.APIEndPoint
42513                             .getOptionControlFile(this.name)
42514                             .$promise
42515                             .then(function (result) {
42516                             controller.options = result.info;
42517                         });
42518                         this.APIEndPoint
42519                             .getDirectories()
42520                             .$promise
42521                             .then(function (result) {
42522                             controller.dirs = result.info;
42523                         });
42524                         this.heading = "[" + this.index + "]: dcdFilePrint";
42525                         this.isOpen = true;
42526                         this.$scope.$on('close', function () {
42527                             controller.isOpen = false;
42528                         });
42529                         function guid() {
42530                             function s4() {
42531                                 return Math.floor((1 + Math.random()) * 0x10000)
42532                                     .toString(16)
42533                                     .substring(1);
42534                             }
42535                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
42536                                 s4() + '-' + s4() + s4() + s4();
42537                         }
42538                         var uuid = guid();
42539                     }
42540                     CommandController.prototype.submit = function () {
42541                         var opt = [];
42542                         angular.forEach(this.options, function (option) {
42543                             var obj = {
42544                                 name: option.option,
42545                                 arguments: []
42546                             };
42547                             angular.forEach(option.arg, function (arg) {
42548                                 if (arg.input) {
42549                                     if (typeof arg.input === 'object') {
42550                                         obj.arguments.push(arg.input.name);
42551                                     }
42552                                     else {
42553                                         obj.arguments.push(arg.input);
42554                                     }
42555                                 }
42556                             });
42557                             if (obj.arguments.length > 0) {
42558                                 opt.push(obj);
42559                             }
42560                         });
42561                         var execObj = {
42562                             command: this.name,
42563                             workspace: this.workspace.fileId,
42564                             options: opt
42565                         };
42566                         this.APIEndPoint
42567                             .execute(JSON.stringify(execObj))
42568                             .then(function (result) {
42569                             console.log(result);
42570                         });
42571                     };
42572                     CommandController.prototype.removeMySelf = function (index) {
42573                         this.$scope.$destroy();
42574                         this.remove()(index, this.list);
42575                     };
42576                     CommandController.prototype.reloadFiles = function () {
42577                         var _this = this;
42578                         var fileId = this.workspace.fileId;
42579                         this.APIEndPoint
42580                             .getFiles(fileId)
42581                             .$promise
42582                             .then(function (result) {
42583                             var status = result.status;
42584                             if (status === 'success') {
42585                                 _this.files = result.info;
42586                             }
42587                             else {
42588                                 console.log(result.message);
42589                             }
42590                         });
42591                     };
42592                     CommandController.prototype.debug = function () {
42593                         console.log(this.$rootScope);
42594                         var div = angular.element(this.$window.document).find("div");
42595                         var consoleTag;
42596                         var parametersTag;
42597                         angular.forEach(div, function (v) {
42598                             if (v.className === "panel-body console") {
42599                                 consoleTag = v;
42600                             }
42601                             else if (v.className === "row parameters-console") {
42602                                 parametersTag = v;
42603                             }
42604                         });
42605                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
42606                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
42607                         consoleTag.style.height = consoleHeight;
42608                         consoleTag.style.width = consoleWidth;
42609                     };
42610                     CommandController.prototype.help = function () {
42611                         this.APIEndPoint
42612                             .help(this.name)
42613                             .then(function (result) {
42614                             console.log(result);
42615                         });
42616                     };
42617                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
42618                     return CommandController;
42619                 })();
42620                 directives.CommandController = CommandController;
42621             })(directives = app.directives || (app.directives = {}));
42622         })(app || (app = {}));
42623         var app;
42624         (function (app) {
42625             var directives;
42626             (function (directives) {
42627                 var HeaderMenu = (function () {
42628                     function HeaderMenu() {
42629                         this.restrict = 'E';
42630                         this.replace = true;
42631                         this.templateUrl = 'templates/header-menu.html';
42632                         this.controller = 'HeaderMenuController';
42633                         this.controllerAs = 'hmc';
42634                         this.scope = true;
42635                     }
42636                     HeaderMenu.Factory = function () {
42637                         var directive = function () {
42638                             return new HeaderMenu();
42639                         };
42640                         return directive;
42641                     };
42642                     return HeaderMenu;
42643                 })();
42644                 directives.HeaderMenu = HeaderMenu;
42645                 var HeaderMenuController = (function () {
42646                     function HeaderMenuController($state) {
42647                         this.$state = $state;
42648                         this.isExecution = this.$state.current.name === 'execution';
42649                         this.isWorkspace = this.$state.current.name === 'workspace';
42650                         this.isHistory = this.$state.current.name === 'history';
42651                     }
42652                     HeaderMenuController.prototype.transit = function (state) {
42653                         this.$state.go(state);
42654                     };
42655                     HeaderMenuController.$inject = ['$state'];
42656                     return HeaderMenuController;
42657                 })();
42658                 directives.HeaderMenuController = HeaderMenuController;
42659             })(directives = app.directives || (app.directives = {}));
42660         })(app || (app = {}));
42661         var app;
42662         (function (app) {
42663             var directives;
42664             (function (directives) {
42665                 var Option = (function () {
42666                     function Option() {
42667                         this.restrict = 'E';
42668                         this.replace = true;
42669                         this.controller = 'optionController';
42670                         this.bindToController = {
42671                             info: '=',
42672                             files: '='
42673                         };
42674                         this.scope = true;
42675                         this.templateUrl = 'templates/option.html';
42676                         this.controllerAs = 'ctrl';
42677                     }
42678                     Option.Factory = function () {
42679                         var directive = function () {
42680                             return new Option();
42681                         };
42682                         directive.$inject = [];
42683                         return directive;
42684                     };
42685                     return Option;
42686                 })();
42687                 directives.Option = Option;
42688                 var OptionController = (function () {
42689                     function OptionController() {
42690                         var controller = this;
42691                         angular.forEach(controller.info.arg, function (arg) {
42692                             if (arg.initialValue) {
42693                                 if (arg.formType === 'number') {
42694                                     arg.input = parseInt(arg.initialValue);
42695                                 }
42696                                 else {
42697                                     arg.input = arg.initialValue;
42698                                 }
42699                             }
42700                         });
42701                     }
42702                     OptionController.$inject = [];
42703                     return OptionController;
42704                 })();
42705                 directives.OptionController = OptionController;
42706             })(directives = app.directives || (app.directives = {}));
42707         })(app || (app = {}));
42708         var app;
42709         (function (app) {
42710             var directives;
42711             (function (directives) {
42712                 var Directory = (function () {
42713                     function Directory() {
42714                         this.restrict = 'E';
42715                         this.replace = true;
42716                         this.controller = 'directoryController';
42717                         this.controllerAs = 'ctrl';
42718                         this.bindToController = {
42719                             info: '=',
42720                             add: '&',
42721                             list: '=',
42722                             files: '='
42723                         };
42724                         this.templateUrl = 'templates/directory.html';
42725                     }
42726                     Directory.Factory = function () {
42727                         var directive = function () {
42728                             return new Directory();
42729                         };
42730                         return directive;
42731                     };
42732                     return Directory;
42733                 })();
42734                 directives.Directory = Directory;
42735                 var DirectoryController = (function () {
42736                     function DirectoryController(APIEndPoint, $scope) {
42737                         this.APIEndPoint = APIEndPoint;
42738                         this.$scope = $scope;
42739                         var controller = this;
42740                         this.APIEndPoint
42741                             .getFiles(this.info.fileId)
42742                             .$promise
42743                             .then(function (result) {
42744                             if (result.status === 'success') {
42745                                 controller.files = result.info;
42746                                 angular.forEach(result.info, function (file) {
42747                                     if (file.fileType === '0') {
42748                                         var o = file;
42749                                         if (controller.info.path === '/') {
42750                                             o.path = '/' + file.name;
42751                                         }
42752                                         else {
42753                                             o.path = controller.info.path + '/' + file.name;
42754                                         }
42755                                         controller.add()(o, controller.list);
42756                                     }
42757                                 });
42758                             }
42759                             ;
42760                         });
42761                     }
42762                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
42763                     return DirectoryController;
42764                 })();
42765                 directives.DirectoryController = DirectoryController;
42766             })(directives = app.directives || (app.directives = {}));
42767         })(app || (app = {}));
42768         var app;
42769         (function (app) {
42770             var controllers;
42771             (function (controllers) {
42772                 var Execution = (function () {
42773                     function Execution(MyModal, $scope) {
42774                         this.MyModal = MyModal;
42775                         this.$scope = $scope;
42776                         this.commandInfoList = [];
42777                     }
42778                     ;
42779                     Execution.prototype.add = function () {
42780                         this.$scope.$broadcast('close');
42781                         var commandInfoList = this.commandInfoList;
42782                         var commandInstance = this.MyModal.selectCommand();
42783                         commandInstance
42784                             .result
42785                             .then(function (command) {
42786                             commandInfoList.push(new app.declares.CommandInfo(command));
42787                         });
42788                     };
42789                     Execution.prototype.open = function () {
42790                         var result = this.MyModal.open('SelectCommand');
42791                         console.log(result);
42792                     };
42793                     Execution.prototype.remove = function (index, list) {
42794                         list.splice(index, 1);
42795                     };
42796                     Execution.prototype.close = function () {
42797                         console.log("close");
42798                     };
42799                     Execution.$inject = ['MyModal', '$scope'];
42800                     return Execution;
42801                 })();
42802                 controllers.Execution = Execution;
42803             })(controllers = app.controllers || (app.controllers = {}));
42804         })(app || (app = {}));
42805         var app;
42806         (function (app) {
42807             var controllers;
42808             (function (controllers) {
42809                 var Workspace = (function () {
42810                     function Workspace($scope, APIEndPoint, MyModal) {
42811                         this.$scope = $scope;
42812                         this.APIEndPoint = APIEndPoint;
42813                         this.MyModal = MyModal;
42814                         this.directoryList = [];
42815                         var controller = this;
42816                         var directoryList = this.directoryList;
42817                         var o = {
42818                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
42819                             name: '',
42820                             parentId: '',
42821                             fileType: '',
42822                             createdAt: '',
42823                             updatedAt: '',
42824                             path: '/'
42825                         };
42826                         directoryList.push(o);
42827                     }
42828                     Workspace.prototype.addDirectory = function (info, directoryList) {
42829                         directoryList.push(info);
42830                     };
42831                     Workspace.prototype.debug = function () {
42832                         this.MyModal.preview();
42833                     };
42834                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
42835                     return Workspace;
42836                 })();
42837                 controllers.Workspace = Workspace;
42838             })(controllers = app.controllers || (app.controllers = {}));
42839         })(app || (app = {}));
42840         var app;
42841         (function (app) {
42842             var controllers;
42843             (function (controllers) {
42844                 var History = (function () {
42845                     function History($scope) {
42846                         this.page = "History";
42847                     }
42848                     History.$inject = ['$scope'];
42849                     return History;
42850                 })();
42851                 controllers.History = History;
42852             })(controllers = app.controllers || (app.controllers = {}));
42853         })(app || (app = {}));
42854         var app;
42855         (function (app) {
42856             var controllers;
42857             (function (controllers) {
42858                 var SelectCommand = (function () {
42859                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
42860                         this.APIEndPoint = APIEndPoint;
42861                         this.$modalInstance = $modalInstance;
42862                         var controller = this;
42863                         this.APIEndPoint
42864                             .getTags()
42865                             .$promise.then(function (result) {
42866                             controller.tags = result.info;
42867                         });
42868                         this.APIEndPoint
42869                             .getCommands()
42870                             .$promise.then(function (result) {
42871                             controller.commands = result.info;
42872                         });
42873                         this.currentTag = 'all';
42874                     }
42875                     SelectCommand.prototype.changeTag = function (tag) {
42876                         this.currentTag = tag;
42877                     };
42878                     SelectCommand.prototype.selectCommand = function (command) {
42879                         this.$modalInstance.close(command);
42880                     };
42881                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42882                     return SelectCommand;
42883                 })();
42884                 controllers.SelectCommand = SelectCommand;
42885             })(controllers = app.controllers || (app.controllers = {}));
42886         })(app || (app = {}));
42887         var app;
42888         (function (app) {
42889             var controllers;
42890             (function (controllers) {
42891                 var Preview = (function () {
42892                     function Preview($scope, APIEndPoint, $modalInstance) {
42893                         this.APIEndPoint = APIEndPoint;
42894                         this.$modalInstance = $modalInstance;
42895                         var controller = this;
42896                         console.log('preview');
42897                     }
42898                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42899                     return Preview;
42900                 })();
42901                 controllers.Preview = Preview;
42902             })(controllers = app.controllers || (app.controllers = {}));
42903         })(app || (app = {}));
42904         var filters;
42905         (function (filters) {
42906             function Tag() {
42907                 return function (commands, tag) {
42908                     var result = [];
42909                     angular.forEach(commands, function (command) {
42910                         var flag = false;
42911                         angular.forEach(command.tags, function (value) {
42912                             if (tag === value)
42913                                 flag = true;
42914                         });
42915                         if (flag)
42916                             result.push(command);
42917                     });
42918                     return result;
42919                 };
42920             }
42921             filters.Tag = Tag;
42922         })(filters || (filters = {}));
42923         var app;
42924         (function (app) {
42925             'use strict';
42926             var appName = 'zephyr';
42927             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
42928             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
42929                 $urlRouterProvider.otherwise('/execution');
42930                 $locationProvider.html5Mode({
42931                     enabled: true,
42932                     requireBase: false
42933                 });
42934                 $stateProvider
42935                     .state('execution', {
42936                     url: '/execution',
42937                     templateUrl: 'templates/execution.html',
42938                     controller: 'executionController',
42939                     controllerAs: 'c'
42940                 })
42941                     .state('workspace', {
42942                     url: '/workspace',
42943                     templateUrl: 'templates/workspace.html',
42944                     controller: 'workspaceController',
42945                     controllerAs: 'c'
42946                 })
42947                     .state('history', {
42948                     url: '/history',
42949                     templateUrl: 'templates/history.html',
42950                     controller: 'historyController',
42951                     controllerAs: 'c'
42952                 });
42953             });
42954             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
42955             app.zephyr.service('MyModal', app.services.MyModal);
42956             app.zephyr.service('WebSocket', app.services.WebSocket);
42957             app.zephyr.filter('Tag', filters.Tag);
42958             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
42959             app.zephyr.controller('previewController', app.controllers.Preview);
42960             app.zephyr.controller('executionController', app.controllers.Execution);
42961             app.zephyr.controller('workspaceController', app.controllers.Workspace);
42962             app.zephyr.controller('historyController', app.controllers.History);
42963             app.zephyr.controller('commandController', app.directives.CommandController);
42964             app.zephyr.controller('optionController', app.directives.OptionController);
42965             app.zephyr.controller('directoryController', app.directives.DirectoryController);
42966             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
42967             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
42968             app.zephyr.directive('command', app.directives.Command.Factory());
42969             app.zephyr.directive('option', app.directives.Option.Factory());
42970             app.zephyr.directive('directory', app.directives.Directory.Factory());
42971         })(app || (app = {}));
42972
42973
42974 /***/ },
42975 /* 11 */
42976 /***/ function(module, exports) {
42977
42978         var app;
42979         (function (app) {
42980             var declares;
42981             (function (declares) {
42982                 var CommandInfo = (function () {
42983                     function CommandInfo(name) {
42984                         this.name = name;
42985                     }
42986                     return CommandInfo;
42987                 })();
42988                 declares.CommandInfo = CommandInfo;
42989             })(declares = app.declares || (app.declares = {}));
42990         })(app || (app = {}));
42991         var app;
42992         (function (app) {
42993             var services;
42994             (function (services) {
42995                 var APIEndPoint = (function () {
42996                     function APIEndPoint($resource, $http) {
42997                         this.$resource = $resource;
42998                         this.$http = $http;
42999                     }
43000                     APIEndPoint.prototype.resource = function (endPoint, data) {
43001                         var customAction = {
43002                             method: 'GET',
43003                             isArray: false
43004                         };
43005                         var execute = {
43006                             method: 'POST',
43007                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
43008                         };
43009                         return this.$resource(endPoint, {}, { execute: execute });
43010                     };
43011                     APIEndPoint.prototype.getOptionControlFile = function (command) {
43012                         var endPoint = '/api/v1/optionControlFile/' + command;
43013                         return this.resource(endPoint, {}).get();
43014                     };
43015                     APIEndPoint.prototype.getFiles = function (fileId) {
43016                         var endPoint = '/api/v1/workspace';
43017                         if (fileId) {
43018                             endPoint += '/' + fileId;
43019                         }
43020                         return this.resource(endPoint, {}).get();
43021                     };
43022                     APIEndPoint.prototype.getDirectories = function () {
43023                         var endPoint = '/api/v1/all/workspace/directory';
43024                         return this.resource(endPoint, {}).get();
43025                     };
43026                     APIEndPoint.prototype.getTags = function () {
43027                         var endPoint = '/api/v1/tagList';
43028                         return this.resource(endPoint, {}).get();
43029                     };
43030                     APIEndPoint.prototype.getCommands = function () {
43031                         var endPoint = '/api/v1/commandList';
43032                         return this.resource(endPoint, {}).get();
43033                     };
43034                     APIEndPoint.prototype.execute = function (data) {
43035                         var endPoint = '/api/v1/execution';
43036                         var fd = new FormData();
43037                         fd.append('data', data);
43038                         return this.$http.post(endPoint, fd, {
43039                             headers: { 'Content-Type': undefined },
43040                             transformRequest: angular.identity
43041                         });
43042                     };
43043                     APIEndPoint.prototype.debug = function () {
43044                         var endPoint = '/api/v1/debug';
43045                         return this.$http.get(endPoint);
43046                     };
43047                     APIEndPoint.prototype.help = function (command) {
43048                         var endPoint = '/api/v1/help/' + command;
43049                         return this.$http.get(endPoint);
43050                     };
43051                     return APIEndPoint;
43052                 })();
43053                 services.APIEndPoint = APIEndPoint;
43054             })(services = app.services || (app.services = {}));
43055         })(app || (app = {}));
43056         var app;
43057         (function (app) {
43058             var services;
43059             (function (services) {
43060                 var MyModal = (function () {
43061                     function MyModal($uibModal) {
43062                         this.$uibModal = $uibModal;
43063                         this.modalOption = {
43064                             backdrop: true,
43065                             controller: null,
43066                             templateUrl: null,
43067                             size: null
43068                         };
43069                     }
43070                     MyModal.prototype.open = function (modalName) {
43071                         if (modalName === 'SelectCommand') {
43072                             this.modalOption.templateUrl = 'templates/select-command.html';
43073                             this.modalOption.size = 'lg';
43074                         }
43075                         return this.$uibModal.open(this.modalOption);
43076                     };
43077                     MyModal.prototype.selectCommand = function () {
43078                         this.modalOption.templateUrl = 'templates/select-command.html';
43079                         this.modalOption.controller = 'selectCommandController';
43080                         this.modalOption.controllerAs = 'c';
43081                         this.modalOption.size = 'lg';
43082                         return this.$uibModal.open(this.modalOption);
43083                     };
43084                     MyModal.prototype.preview = function () {
43085                         this.modalOption.templateUrl = 'templates/preview.html';
43086                         this.modalOption.controller = 'previewController';
43087                         this.modalOption.controllerAs = 'c';
43088                         this.modalOption.size = 'lg';
43089                         return this.$uibModal.open(this.modalOption);
43090                     };
43091                     MyModal.$inject = ['$uibModal'];
43092                     return MyModal;
43093                 })();
43094                 services.MyModal = MyModal;
43095             })(services = app.services || (app.services = {}));
43096         })(app || (app = {}));
43097         var app;
43098         (function (app) {
43099             var services;
43100             (function (services) {
43101                 var WebSocket = (function () {
43102                     function WebSocket($rootScope) {
43103                         this.$rootScope = $rootScope;
43104                         this.socket = io.connect();
43105                     }
43106                     WebSocket.prototype.on = function (eventName, callback) {
43107                         var socket = this.socket;
43108                         var rootScope = this.$rootScope;
43109                         socket.on(eventName, function () {
43110                             var args = arguments;
43111                             rootScope.$apply(function () {
43112                                 callback.apply(socket, args);
43113                             });
43114                         });
43115                     };
43116                     WebSocket.prototype.emit = function (eventName, data, callback) {
43117                         var socket = this.socket;
43118                         var rootScope = this.$rootScope;
43119                         this.socket.emit(eventName, data, function () {
43120                             var args = arguments;
43121                             rootScope.$apply(function () {
43122                                 if (callback)
43123                                     callback.apply(socket, args);
43124                             });
43125                         });
43126                     };
43127                     return WebSocket;
43128                 })();
43129                 services.WebSocket = WebSocket;
43130             })(services = app.services || (app.services = {}));
43131         })(app || (app = {}));
43132         var app;
43133         (function (app) {
43134             var directives;
43135             (function (directives) {
43136                 var Command = (function () {
43137                     function Command() {
43138                         this.restrict = 'E';
43139                         this.replace = true;
43140                         this.scope = true;
43141                         this.controller = 'commandController';
43142                         this.controllerAs = 'ctrl';
43143                         this.bindToController = {
43144                             index: '=',
43145                             name: '=',
43146                             remove: '&',
43147                             list: '='
43148                         };
43149                         this.templateUrl = 'templates/command.html';
43150                     }
43151                     Command.Factory = function () {
43152                         var directive = function () {
43153                             return new Command();
43154                         };
43155                         directive.$inject = [];
43156                         return directive;
43157                     };
43158                     return Command;
43159                 })();
43160                 directives.Command = Command;
43161                 var CommandController = (function () {
43162                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
43163                         this.APIEndPoint = APIEndPoint;
43164                         this.$scope = $scope;
43165                         this.MyModal = MyModal;
43166                         this.WebSocket = WebSocket;
43167                         this.$window = $window;
43168                         this.$rootScope = $rootScope;
43169                         var controller = this;
43170                         this.APIEndPoint
43171                             .getOptionControlFile(this.name)
43172                             .$promise
43173                             .then(function (result) {
43174                             controller.options = result.info;
43175                         });
43176                         this.APIEndPoint
43177                             .getDirectories()
43178                             .$promise
43179                             .then(function (result) {
43180                             controller.dirs = result.info;
43181                         });
43182                         this.heading = "[" + this.index + "]: dcdFilePrint";
43183                         this.isOpen = true;
43184                         this.$scope.$on('close', function () {
43185                             controller.isOpen = false;
43186                         });
43187                         function guid() {
43188                             function s4() {
43189                                 return Math.floor((1 + Math.random()) * 0x10000)
43190                                     .toString(16)
43191                                     .substring(1);
43192                             }
43193                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
43194                                 s4() + '-' + s4() + s4() + s4();
43195                         }
43196                         var uuid = guid();
43197                     }
43198                     CommandController.prototype.submit = function () {
43199                         var opt = [];
43200                         angular.forEach(this.options, function (option) {
43201                             var obj = {
43202                                 name: option.option,
43203                                 arguments: []
43204                             };
43205                             angular.forEach(option.arg, function (arg) {
43206                                 if (arg.input) {
43207                                     if (typeof arg.input === 'object') {
43208                                         obj.arguments.push(arg.input.name);
43209                                     }
43210                                     else {
43211                                         obj.arguments.push(arg.input);
43212                                     }
43213                                 }
43214                             });
43215                             if (obj.arguments.length > 0) {
43216                                 opt.push(obj);
43217                             }
43218                         });
43219                         var execObj = {
43220                             command: this.name,
43221                             workspace: this.workspace.fileId,
43222                             options: opt
43223                         };
43224                         this.APIEndPoint
43225                             .execute(JSON.stringify(execObj))
43226                             .then(function (result) {
43227                             console.log(result);
43228                         });
43229                     };
43230                     CommandController.prototype.removeMySelf = function (index) {
43231                         this.$scope.$destroy();
43232                         this.remove()(index, this.list);
43233                     };
43234                     CommandController.prototype.reloadFiles = function () {
43235                         var _this = this;
43236                         var fileId = this.workspace.fileId;
43237                         this.APIEndPoint
43238                             .getFiles(fileId)
43239                             .$promise
43240                             .then(function (result) {
43241                             var status = result.status;
43242                             if (status === 'success') {
43243                                 _this.files = result.info;
43244                             }
43245                             else {
43246                                 console.log(result.message);
43247                             }
43248                         });
43249                     };
43250                     CommandController.prototype.debug = function () {
43251                         console.log(this.$rootScope);
43252                         var div = angular.element(this.$window.document).find("div");
43253                         var consoleTag;
43254                         var parametersTag;
43255                         angular.forEach(div, function (v) {
43256                             if (v.className === "panel-body console") {
43257                                 consoleTag = v;
43258                             }
43259                             else if (v.className === "row parameters-console") {
43260                                 parametersTag = v;
43261                             }
43262                         });
43263                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
43264                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
43265                         consoleTag.style.height = consoleHeight;
43266                         consoleTag.style.width = consoleWidth;
43267                     };
43268                     CommandController.prototype.help = function () {
43269                         this.APIEndPoint
43270                             .help(this.name)
43271                             .then(function (result) {
43272                             console.log(result);
43273                         });
43274                     };
43275                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
43276                     return CommandController;
43277                 })();
43278                 directives.CommandController = CommandController;
43279             })(directives = app.directives || (app.directives = {}));
43280         })(app || (app = {}));
43281         var app;
43282         (function (app) {
43283             var directives;
43284             (function (directives) {
43285                 var HeaderMenu = (function () {
43286                     function HeaderMenu() {
43287                         this.restrict = 'E';
43288                         this.replace = true;
43289                         this.templateUrl = 'templates/header-menu.html';
43290                         this.controller = 'HeaderMenuController';
43291                         this.controllerAs = 'hmc';
43292                         this.scope = true;
43293                     }
43294                     HeaderMenu.Factory = function () {
43295                         var directive = function () {
43296                             return new HeaderMenu();
43297                         };
43298                         return directive;
43299                     };
43300                     return HeaderMenu;
43301                 })();
43302                 directives.HeaderMenu = HeaderMenu;
43303                 var HeaderMenuController = (function () {
43304                     function HeaderMenuController($state) {
43305                         this.$state = $state;
43306                         this.isExecution = this.$state.current.name === 'execution';
43307                         this.isWorkspace = this.$state.current.name === 'workspace';
43308                         this.isHistory = this.$state.current.name === 'history';
43309                     }
43310                     HeaderMenuController.prototype.transit = function (state) {
43311                         this.$state.go(state);
43312                     };
43313                     HeaderMenuController.$inject = ['$state'];
43314                     return HeaderMenuController;
43315                 })();
43316                 directives.HeaderMenuController = HeaderMenuController;
43317             })(directives = app.directives || (app.directives = {}));
43318         })(app || (app = {}));
43319         var app;
43320         (function (app) {
43321             var directives;
43322             (function (directives) {
43323                 var Option = (function () {
43324                     function Option() {
43325                         this.restrict = 'E';
43326                         this.replace = true;
43327                         this.controller = 'optionController';
43328                         this.bindToController = {
43329                             info: '=',
43330                             files: '='
43331                         };
43332                         this.scope = true;
43333                         this.templateUrl = 'templates/option.html';
43334                         this.controllerAs = 'ctrl';
43335                     }
43336                     Option.Factory = function () {
43337                         var directive = function () {
43338                             return new Option();
43339                         };
43340                         directive.$inject = [];
43341                         return directive;
43342                     };
43343                     return Option;
43344                 })();
43345                 directives.Option = Option;
43346                 var OptionController = (function () {
43347                     function OptionController() {
43348                         var controller = this;
43349                         angular.forEach(controller.info.arg, function (arg) {
43350                             if (arg.initialValue) {
43351                                 if (arg.formType === 'number') {
43352                                     arg.input = parseInt(arg.initialValue);
43353                                 }
43354                                 else {
43355                                     arg.input = arg.initialValue;
43356                                 }
43357                             }
43358                         });
43359                     }
43360                     OptionController.$inject = [];
43361                     return OptionController;
43362                 })();
43363                 directives.OptionController = OptionController;
43364             })(directives = app.directives || (app.directives = {}));
43365         })(app || (app = {}));
43366         var app;
43367         (function (app) {
43368             var directives;
43369             (function (directives) {
43370                 var Directory = (function () {
43371                     function Directory() {
43372                         this.restrict = 'E';
43373                         this.replace = true;
43374                         this.controller = 'directoryController';
43375                         this.controllerAs = 'ctrl';
43376                         this.bindToController = {
43377                             info: '=',
43378                             add: '&',
43379                             list: '=',
43380                             files: '='
43381                         };
43382                         this.templateUrl = 'templates/directory.html';
43383                     }
43384                     Directory.Factory = function () {
43385                         var directive = function () {
43386                             return new Directory();
43387                         };
43388                         return directive;
43389                     };
43390                     return Directory;
43391                 })();
43392                 directives.Directory = Directory;
43393                 var DirectoryController = (function () {
43394                     function DirectoryController(APIEndPoint, $scope) {
43395                         this.APIEndPoint = APIEndPoint;
43396                         this.$scope = $scope;
43397                         var controller = this;
43398                         this.APIEndPoint
43399                             .getFiles(this.info.fileId)
43400                             .$promise
43401                             .then(function (result) {
43402                             if (result.status === 'success') {
43403                                 controller.files = result.info;
43404                                 angular.forEach(result.info, function (file) {
43405                                     if (file.fileType === '0') {
43406                                         var o = file;
43407                                         if (controller.info.path === '/') {
43408                                             o.path = '/' + file.name;
43409                                         }
43410                                         else {
43411                                             o.path = controller.info.path + '/' + file.name;
43412                                         }
43413                                         controller.add()(o, controller.list);
43414                                     }
43415                                 });
43416                             }
43417                             ;
43418                         });
43419                     }
43420                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
43421                     return DirectoryController;
43422                 })();
43423                 directives.DirectoryController = DirectoryController;
43424             })(directives = app.directives || (app.directives = {}));
43425         })(app || (app = {}));
43426         var app;
43427         (function (app) {
43428             var controllers;
43429             (function (controllers) {
43430                 var Execution = (function () {
43431                     function Execution(MyModal, $scope) {
43432                         this.MyModal = MyModal;
43433                         this.$scope = $scope;
43434                         this.commandInfoList = [];
43435                     }
43436                     ;
43437                     Execution.prototype.add = function () {
43438                         this.$scope.$broadcast('close');
43439                         var commandInfoList = this.commandInfoList;
43440                         var commandInstance = this.MyModal.selectCommand();
43441                         commandInstance
43442                             .result
43443                             .then(function (command) {
43444                             commandInfoList.push(new app.declares.CommandInfo(command));
43445                         });
43446                     };
43447                     Execution.prototype.open = function () {
43448                         var result = this.MyModal.open('SelectCommand');
43449                         console.log(result);
43450                     };
43451                     Execution.prototype.remove = function (index, list) {
43452                         list.splice(index, 1);
43453                     };
43454                     Execution.prototype.close = function () {
43455                         console.log("close");
43456                     };
43457                     Execution.$inject = ['MyModal', '$scope'];
43458                     return Execution;
43459                 })();
43460                 controllers.Execution = Execution;
43461             })(controllers = app.controllers || (app.controllers = {}));
43462         })(app || (app = {}));
43463         var app;
43464         (function (app) {
43465             var controllers;
43466             (function (controllers) {
43467                 var Workspace = (function () {
43468                     function Workspace($scope, APIEndPoint, MyModal) {
43469                         this.$scope = $scope;
43470                         this.APIEndPoint = APIEndPoint;
43471                         this.MyModal = MyModal;
43472                         this.directoryList = [];
43473                         var controller = this;
43474                         var directoryList = this.directoryList;
43475                         var o = {
43476                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
43477                             name: '',
43478                             parentId: '',
43479                             fileType: '',
43480                             createdAt: '',
43481                             updatedAt: '',
43482                             path: '/'
43483                         };
43484                         directoryList.push(o);
43485                     }
43486                     Workspace.prototype.addDirectory = function (info, directoryList) {
43487                         directoryList.push(info);
43488                     };
43489                     Workspace.prototype.debug = function () {
43490                         this.MyModal.preview();
43491                     };
43492                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
43493                     return Workspace;
43494                 })();
43495                 controllers.Workspace = Workspace;
43496             })(controllers = app.controllers || (app.controllers = {}));
43497         })(app || (app = {}));
43498         var app;
43499         (function (app) {
43500             var controllers;
43501             (function (controllers) {
43502                 var History = (function () {
43503                     function History($scope) {
43504                         this.page = "History";
43505                     }
43506                     History.$inject = ['$scope'];
43507                     return History;
43508                 })();
43509                 controllers.History = History;
43510             })(controllers = app.controllers || (app.controllers = {}));
43511         })(app || (app = {}));
43512         var app;
43513         (function (app) {
43514             var controllers;
43515             (function (controllers) {
43516                 var SelectCommand = (function () {
43517                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
43518                         this.APIEndPoint = APIEndPoint;
43519                         this.$modalInstance = $modalInstance;
43520                         var controller = this;
43521                         this.APIEndPoint
43522                             .getTags()
43523                             .$promise.then(function (result) {
43524                             controller.tags = result.info;
43525                         });
43526                         this.APIEndPoint
43527                             .getCommands()
43528                             .$promise.then(function (result) {
43529                             controller.commands = result.info;
43530                         });
43531                         this.currentTag = 'all';
43532                     }
43533                     SelectCommand.prototype.changeTag = function (tag) {
43534                         this.currentTag = tag;
43535                     };
43536                     SelectCommand.prototype.selectCommand = function (command) {
43537                         this.$modalInstance.close(command);
43538                     };
43539                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43540                     return SelectCommand;
43541                 })();
43542                 controllers.SelectCommand = SelectCommand;
43543             })(controllers = app.controllers || (app.controllers = {}));
43544         })(app || (app = {}));
43545         var app;
43546         (function (app) {
43547             var controllers;
43548             (function (controllers) {
43549                 var Preview = (function () {
43550                     function Preview($scope, APIEndPoint, $modalInstance) {
43551                         this.APIEndPoint = APIEndPoint;
43552                         this.$modalInstance = $modalInstance;
43553                         var controller = this;
43554                         console.log('preview');
43555                     }
43556                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43557                     return Preview;
43558                 })();
43559                 controllers.Preview = Preview;
43560             })(controllers = app.controllers || (app.controllers = {}));
43561         })(app || (app = {}));
43562         var filters;
43563         (function (filters) {
43564             function Tag() {
43565                 return function (commands, tag) {
43566                     var result = [];
43567                     angular.forEach(commands, function (command) {
43568                         var flag = false;
43569                         angular.forEach(command.tags, function (value) {
43570                             if (tag === value)
43571                                 flag = true;
43572                         });
43573                         if (flag)
43574                             result.push(command);
43575                     });
43576                     return result;
43577                 };
43578             }
43579             filters.Tag = Tag;
43580         })(filters || (filters = {}));
43581         var app;
43582         (function (app) {
43583             'use strict';
43584             var appName = 'zephyr';
43585             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
43586             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
43587                 $urlRouterProvider.otherwise('/execution');
43588                 $locationProvider.html5Mode({
43589                     enabled: true,
43590                     requireBase: false
43591                 });
43592                 $stateProvider
43593                     .state('execution', {
43594                     url: '/execution',
43595                     templateUrl: 'templates/execution.html',
43596                     controller: 'executionController',
43597                     controllerAs: 'c'
43598                 })
43599                     .state('workspace', {
43600                     url: '/workspace',
43601                     templateUrl: 'templates/workspace.html',
43602                     controller: 'workspaceController',
43603                     controllerAs: 'c'
43604                 })
43605                     .state('history', {
43606                     url: '/history',
43607                     templateUrl: 'templates/history.html',
43608                     controller: 'historyController',
43609                     controllerAs: 'c'
43610                 });
43611             });
43612             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
43613             app.zephyr.service('MyModal', app.services.MyModal);
43614             app.zephyr.service('WebSocket', app.services.WebSocket);
43615             app.zephyr.filter('Tag', filters.Tag);
43616             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
43617             app.zephyr.controller('previewController', app.controllers.Preview);
43618             app.zephyr.controller('executionController', app.controllers.Execution);
43619             app.zephyr.controller('workspaceController', app.controllers.Workspace);
43620             app.zephyr.controller('historyController', app.controllers.History);
43621             app.zephyr.controller('commandController', app.directives.CommandController);
43622             app.zephyr.controller('optionController', app.directives.OptionController);
43623             app.zephyr.controller('directoryController', app.directives.DirectoryController);
43624             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
43625             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
43626             app.zephyr.directive('command', app.directives.Command.Factory());
43627             app.zephyr.directive('option', app.directives.Option.Factory());
43628             app.zephyr.directive('directory', app.directives.Directory.Factory());
43629         })(app || (app = {}));
43630
43631
43632 /***/ },
43633 /* 12 */
43634 /***/ function(module, exports) {
43635
43636         var app;
43637         (function (app) {
43638             var declares;
43639             (function (declares) {
43640                 var CommandInfo = (function () {
43641                     function CommandInfo(name) {
43642                         this.name = name;
43643                     }
43644                     return CommandInfo;
43645                 })();
43646                 declares.CommandInfo = CommandInfo;
43647             })(declares = app.declares || (app.declares = {}));
43648         })(app || (app = {}));
43649         var app;
43650         (function (app) {
43651             var services;
43652             (function (services) {
43653                 var APIEndPoint = (function () {
43654                     function APIEndPoint($resource, $http) {
43655                         this.$resource = $resource;
43656                         this.$http = $http;
43657                     }
43658                     APIEndPoint.prototype.resource = function (endPoint, data) {
43659                         var customAction = {
43660                             method: 'GET',
43661                             isArray: false
43662                         };
43663                         var execute = {
43664                             method: 'POST',
43665                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
43666                         };
43667                         return this.$resource(endPoint, {}, { execute: execute });
43668                     };
43669                     APIEndPoint.prototype.getOptionControlFile = function (command) {
43670                         var endPoint = '/api/v1/optionControlFile/' + command;
43671                         return this.resource(endPoint, {}).get();
43672                     };
43673                     APIEndPoint.prototype.getFiles = function (fileId) {
43674                         var endPoint = '/api/v1/workspace';
43675                         if (fileId) {
43676                             endPoint += '/' + fileId;
43677                         }
43678                         return this.resource(endPoint, {}).get();
43679                     };
43680                     APIEndPoint.prototype.getDirectories = function () {
43681                         var endPoint = '/api/v1/all/workspace/directory';
43682                         return this.resource(endPoint, {}).get();
43683                     };
43684                     APIEndPoint.prototype.getTags = function () {
43685                         var endPoint = '/api/v1/tagList';
43686                         return this.resource(endPoint, {}).get();
43687                     };
43688                     APIEndPoint.prototype.getCommands = function () {
43689                         var endPoint = '/api/v1/commandList';
43690                         return this.resource(endPoint, {}).get();
43691                     };
43692                     APIEndPoint.prototype.execute = function (data) {
43693                         var endPoint = '/api/v1/execution';
43694                         var fd = new FormData();
43695                         fd.append('data', data);
43696                         return this.$http.post(endPoint, fd, {
43697                             headers: { 'Content-Type': undefined },
43698                             transformRequest: angular.identity
43699                         });
43700                     };
43701                     APIEndPoint.prototype.debug = function () {
43702                         var endPoint = '/api/v1/debug';
43703                         return this.$http.get(endPoint);
43704                     };
43705                     APIEndPoint.prototype.help = function (command) {
43706                         var endPoint = '/api/v1/help/' + command;
43707                         return this.$http.get(endPoint);
43708                     };
43709                     return APIEndPoint;
43710                 })();
43711                 services.APIEndPoint = APIEndPoint;
43712             })(services = app.services || (app.services = {}));
43713         })(app || (app = {}));
43714         var app;
43715         (function (app) {
43716             var services;
43717             (function (services) {
43718                 var MyModal = (function () {
43719                     function MyModal($uibModal) {
43720                         this.$uibModal = $uibModal;
43721                         this.modalOption = {
43722                             backdrop: true,
43723                             controller: null,
43724                             templateUrl: null,
43725                             size: null
43726                         };
43727                     }
43728                     MyModal.prototype.open = function (modalName) {
43729                         if (modalName === 'SelectCommand') {
43730                             this.modalOption.templateUrl = 'templates/select-command.html';
43731                             this.modalOption.size = 'lg';
43732                         }
43733                         return this.$uibModal.open(this.modalOption);
43734                     };
43735                     MyModal.prototype.selectCommand = function () {
43736                         this.modalOption.templateUrl = 'templates/select-command.html';
43737                         this.modalOption.controller = 'selectCommandController';
43738                         this.modalOption.controllerAs = 'c';
43739                         this.modalOption.size = 'lg';
43740                         return this.$uibModal.open(this.modalOption);
43741                     };
43742                     MyModal.prototype.preview = function () {
43743                         this.modalOption.templateUrl = 'templates/preview.html';
43744                         this.modalOption.controller = 'previewController';
43745                         this.modalOption.controllerAs = 'c';
43746                         this.modalOption.size = 'lg';
43747                         return this.$uibModal.open(this.modalOption);
43748                     };
43749                     MyModal.$inject = ['$uibModal'];
43750                     return MyModal;
43751                 })();
43752                 services.MyModal = MyModal;
43753             })(services = app.services || (app.services = {}));
43754         })(app || (app = {}));
43755         var app;
43756         (function (app) {
43757             var services;
43758             (function (services) {
43759                 var WebSocket = (function () {
43760                     function WebSocket($rootScope) {
43761                         this.$rootScope = $rootScope;
43762                         this.socket = io.connect();
43763                     }
43764                     WebSocket.prototype.on = function (eventName, callback) {
43765                         var socket = this.socket;
43766                         var rootScope = this.$rootScope;
43767                         socket.on(eventName, function () {
43768                             var args = arguments;
43769                             rootScope.$apply(function () {
43770                                 callback.apply(socket, args);
43771                             });
43772                         });
43773                     };
43774                     WebSocket.prototype.emit = function (eventName, data, callback) {
43775                         var socket = this.socket;
43776                         var rootScope = this.$rootScope;
43777                         this.socket.emit(eventName, data, function () {
43778                             var args = arguments;
43779                             rootScope.$apply(function () {
43780                                 if (callback)
43781                                     callback.apply(socket, args);
43782                             });
43783                         });
43784                     };
43785                     return WebSocket;
43786                 })();
43787                 services.WebSocket = WebSocket;
43788             })(services = app.services || (app.services = {}));
43789         })(app || (app = {}));
43790         var app;
43791         (function (app) {
43792             var directives;
43793             (function (directives) {
43794                 var Command = (function () {
43795                     function Command() {
43796                         this.restrict = 'E';
43797                         this.replace = true;
43798                         this.scope = true;
43799                         this.controller = 'commandController';
43800                         this.controllerAs = 'ctrl';
43801                         this.bindToController = {
43802                             index: '=',
43803                             name: '=',
43804                             remove: '&',
43805                             list: '='
43806                         };
43807                         this.templateUrl = 'templates/command.html';
43808                     }
43809                     Command.Factory = function () {
43810                         var directive = function () {
43811                             return new Command();
43812                         };
43813                         directive.$inject = [];
43814                         return directive;
43815                     };
43816                     return Command;
43817                 })();
43818                 directives.Command = Command;
43819                 var CommandController = (function () {
43820                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
43821                         this.APIEndPoint = APIEndPoint;
43822                         this.$scope = $scope;
43823                         this.MyModal = MyModal;
43824                         this.WebSocket = WebSocket;
43825                         this.$window = $window;
43826                         this.$rootScope = $rootScope;
43827                         var controller = this;
43828                         this.APIEndPoint
43829                             .getOptionControlFile(this.name)
43830                             .$promise
43831                             .then(function (result) {
43832                             controller.options = result.info;
43833                         });
43834                         this.APIEndPoint
43835                             .getDirectories()
43836                             .$promise
43837                             .then(function (result) {
43838                             controller.dirs = result.info;
43839                         });
43840                         this.heading = "[" + this.index + "]: dcdFilePrint";
43841                         this.isOpen = true;
43842                         this.$scope.$on('close', function () {
43843                             controller.isOpen = false;
43844                         });
43845                         function guid() {
43846                             function s4() {
43847                                 return Math.floor((1 + Math.random()) * 0x10000)
43848                                     .toString(16)
43849                                     .substring(1);
43850                             }
43851                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
43852                                 s4() + '-' + s4() + s4() + s4();
43853                         }
43854                         var uuid = guid();
43855                     }
43856                     CommandController.prototype.submit = function () {
43857                         var opt = [];
43858                         angular.forEach(this.options, function (option) {
43859                             var obj = {
43860                                 name: option.option,
43861                                 arguments: []
43862                             };
43863                             angular.forEach(option.arg, function (arg) {
43864                                 if (arg.input) {
43865                                     if (typeof arg.input === 'object') {
43866                                         obj.arguments.push(arg.input.name);
43867                                     }
43868                                     else {
43869                                         obj.arguments.push(arg.input);
43870                                     }
43871                                 }
43872                             });
43873                             if (obj.arguments.length > 0) {
43874                                 opt.push(obj);
43875                             }
43876                         });
43877                         var execObj = {
43878                             command: this.name,
43879                             workspace: this.workspace.fileId,
43880                             options: opt
43881                         };
43882                         this.APIEndPoint
43883                             .execute(JSON.stringify(execObj))
43884                             .then(function (result) {
43885                             console.log(result);
43886                         });
43887                     };
43888                     CommandController.prototype.removeMySelf = function (index) {
43889                         this.$scope.$destroy();
43890                         this.remove()(index, this.list);
43891                     };
43892                     CommandController.prototype.reloadFiles = function () {
43893                         var _this = this;
43894                         var fileId = this.workspace.fileId;
43895                         this.APIEndPoint
43896                             .getFiles(fileId)
43897                             .$promise
43898                             .then(function (result) {
43899                             var status = result.status;
43900                             if (status === 'success') {
43901                                 _this.files = result.info;
43902                             }
43903                             else {
43904                                 console.log(result.message);
43905                             }
43906                         });
43907                     };
43908                     CommandController.prototype.debug = function () {
43909                         console.log(this.$rootScope);
43910                         var div = angular.element(this.$window.document).find("div");
43911                         var consoleTag;
43912                         var parametersTag;
43913                         angular.forEach(div, function (v) {
43914                             if (v.className === "panel-body console") {
43915                                 consoleTag = v;
43916                             }
43917                             else if (v.className === "row parameters-console") {
43918                                 parametersTag = v;
43919                             }
43920                         });
43921                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
43922                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
43923                         consoleTag.style.height = consoleHeight;
43924                         consoleTag.style.width = consoleWidth;
43925                     };
43926                     CommandController.prototype.help = function () {
43927                         this.APIEndPoint
43928                             .help(this.name)
43929                             .then(function (result) {
43930                             console.log(result);
43931                         });
43932                     };
43933                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
43934                     return CommandController;
43935                 })();
43936                 directives.CommandController = CommandController;
43937             })(directives = app.directives || (app.directives = {}));
43938         })(app || (app = {}));
43939         var app;
43940         (function (app) {
43941             var directives;
43942             (function (directives) {
43943                 var HeaderMenu = (function () {
43944                     function HeaderMenu() {
43945                         this.restrict = 'E';
43946                         this.replace = true;
43947                         this.templateUrl = 'templates/header-menu.html';
43948                         this.controller = 'HeaderMenuController';
43949                         this.controllerAs = 'hmc';
43950                         this.scope = true;
43951                     }
43952                     HeaderMenu.Factory = function () {
43953                         var directive = function () {
43954                             return new HeaderMenu();
43955                         };
43956                         return directive;
43957                     };
43958                     return HeaderMenu;
43959                 })();
43960                 directives.HeaderMenu = HeaderMenu;
43961                 var HeaderMenuController = (function () {
43962                     function HeaderMenuController($state) {
43963                         this.$state = $state;
43964                         this.isExecution = this.$state.current.name === 'execution';
43965                         this.isWorkspace = this.$state.current.name === 'workspace';
43966                         this.isHistory = this.$state.current.name === 'history';
43967                     }
43968                     HeaderMenuController.prototype.transit = function (state) {
43969                         this.$state.go(state);
43970                     };
43971                     HeaderMenuController.$inject = ['$state'];
43972                     return HeaderMenuController;
43973                 })();
43974                 directives.HeaderMenuController = HeaderMenuController;
43975             })(directives = app.directives || (app.directives = {}));
43976         })(app || (app = {}));
43977         var app;
43978         (function (app) {
43979             var directives;
43980             (function (directives) {
43981                 var Option = (function () {
43982                     function Option() {
43983                         this.restrict = 'E';
43984                         this.replace = true;
43985                         this.controller = 'optionController';
43986                         this.bindToController = {
43987                             info: '=',
43988                             files: '='
43989                         };
43990                         this.scope = true;
43991                         this.templateUrl = 'templates/option.html';
43992                         this.controllerAs = 'ctrl';
43993                     }
43994                     Option.Factory = function () {
43995                         var directive = function () {
43996                             return new Option();
43997                         };
43998                         directive.$inject = [];
43999                         return directive;
44000                     };
44001                     return Option;
44002                 })();
44003                 directives.Option = Option;
44004                 var OptionController = (function () {
44005                     function OptionController() {
44006                         var controller = this;
44007                         angular.forEach(controller.info.arg, function (arg) {
44008                             if (arg.initialValue) {
44009                                 if (arg.formType === 'number') {
44010                                     arg.input = parseInt(arg.initialValue);
44011                                 }
44012                                 else {
44013                                     arg.input = arg.initialValue;
44014                                 }
44015                             }
44016                         });
44017                     }
44018                     OptionController.$inject = [];
44019                     return OptionController;
44020                 })();
44021                 directives.OptionController = OptionController;
44022             })(directives = app.directives || (app.directives = {}));
44023         })(app || (app = {}));
44024         var app;
44025         (function (app) {
44026             var directives;
44027             (function (directives) {
44028                 var Directory = (function () {
44029                     function Directory() {
44030                         this.restrict = 'E';
44031                         this.replace = true;
44032                         this.controller = 'directoryController';
44033                         this.controllerAs = 'ctrl';
44034                         this.bindToController = {
44035                             info: '=',
44036                             add: '&',
44037                             list: '=',
44038                             files: '='
44039                         };
44040                         this.templateUrl = 'templates/directory.html';
44041                     }
44042                     Directory.Factory = function () {
44043                         var directive = function () {
44044                             return new Directory();
44045                         };
44046                         return directive;
44047                     };
44048                     return Directory;
44049                 })();
44050                 directives.Directory = Directory;
44051                 var DirectoryController = (function () {
44052                     function DirectoryController(APIEndPoint, $scope) {
44053                         this.APIEndPoint = APIEndPoint;
44054                         this.$scope = $scope;
44055                         var controller = this;
44056                         this.APIEndPoint
44057                             .getFiles(this.info.fileId)
44058                             .$promise
44059                             .then(function (result) {
44060                             if (result.status === 'success') {
44061                                 controller.files = result.info;
44062                                 angular.forEach(result.info, function (file) {
44063                                     if (file.fileType === '0') {
44064                                         var o = file;
44065                                         if (controller.info.path === '/') {
44066                                             o.path = '/' + file.name;
44067                                         }
44068                                         else {
44069                                             o.path = controller.info.path + '/' + file.name;
44070                                         }
44071                                         controller.add()(o, controller.list);
44072                                     }
44073                                 });
44074                             }
44075                             ;
44076                         });
44077                     }
44078                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
44079                     return DirectoryController;
44080                 })();
44081                 directives.DirectoryController = DirectoryController;
44082             })(directives = app.directives || (app.directives = {}));
44083         })(app || (app = {}));
44084         var app;
44085         (function (app) {
44086             var controllers;
44087             (function (controllers) {
44088                 var Execution = (function () {
44089                     function Execution(MyModal, $scope) {
44090                         this.MyModal = MyModal;
44091                         this.$scope = $scope;
44092                         this.commandInfoList = [];
44093                     }
44094                     ;
44095                     Execution.prototype.add = function () {
44096                         this.$scope.$broadcast('close');
44097                         var commandInfoList = this.commandInfoList;
44098                         var commandInstance = this.MyModal.selectCommand();
44099                         commandInstance
44100                             .result
44101                             .then(function (command) {
44102                             commandInfoList.push(new app.declares.CommandInfo(command));
44103                         });
44104                     };
44105                     Execution.prototype.open = function () {
44106                         var result = this.MyModal.open('SelectCommand');
44107                         console.log(result);
44108                     };
44109                     Execution.prototype.remove = function (index, list) {
44110                         list.splice(index, 1);
44111                     };
44112                     Execution.prototype.close = function () {
44113                         console.log("close");
44114                     };
44115                     Execution.$inject = ['MyModal', '$scope'];
44116                     return Execution;
44117                 })();
44118                 controllers.Execution = Execution;
44119             })(controllers = app.controllers || (app.controllers = {}));
44120         })(app || (app = {}));
44121         var app;
44122         (function (app) {
44123             var controllers;
44124             (function (controllers) {
44125                 var Workspace = (function () {
44126                     function Workspace($scope, APIEndPoint, MyModal) {
44127                         this.$scope = $scope;
44128                         this.APIEndPoint = APIEndPoint;
44129                         this.MyModal = MyModal;
44130                         this.directoryList = [];
44131                         var controller = this;
44132                         var directoryList = this.directoryList;
44133                         var o = {
44134                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
44135                             name: '',
44136                             parentId: '',
44137                             fileType: '',
44138                             createdAt: '',
44139                             updatedAt: '',
44140                             path: '/'
44141                         };
44142                         directoryList.push(o);
44143                     }
44144                     Workspace.prototype.addDirectory = function (info, directoryList) {
44145                         directoryList.push(info);
44146                     };
44147                     Workspace.prototype.debug = function () {
44148                         this.MyModal.preview();
44149                     };
44150                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
44151                     return Workspace;
44152                 })();
44153                 controllers.Workspace = Workspace;
44154             })(controllers = app.controllers || (app.controllers = {}));
44155         })(app || (app = {}));
44156         var app;
44157         (function (app) {
44158             var controllers;
44159             (function (controllers) {
44160                 var History = (function () {
44161                     function History($scope) {
44162                         this.page = "History";
44163                     }
44164                     History.$inject = ['$scope'];
44165                     return History;
44166                 })();
44167                 controllers.History = History;
44168             })(controllers = app.controllers || (app.controllers = {}));
44169         })(app || (app = {}));
44170         var app;
44171         (function (app) {
44172             var controllers;
44173             (function (controllers) {
44174                 var SelectCommand = (function () {
44175                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
44176                         this.APIEndPoint = APIEndPoint;
44177                         this.$modalInstance = $modalInstance;
44178                         var controller = this;
44179                         this.APIEndPoint
44180                             .getTags()
44181                             .$promise.then(function (result) {
44182                             controller.tags = result.info;
44183                         });
44184                         this.APIEndPoint
44185                             .getCommands()
44186                             .$promise.then(function (result) {
44187                             controller.commands = result.info;
44188                         });
44189                         this.currentTag = 'all';
44190                     }
44191                     SelectCommand.prototype.changeTag = function (tag) {
44192                         this.currentTag = tag;
44193                     };
44194                     SelectCommand.prototype.selectCommand = function (command) {
44195                         this.$modalInstance.close(command);
44196                     };
44197                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44198                     return SelectCommand;
44199                 })();
44200                 controllers.SelectCommand = SelectCommand;
44201             })(controllers = app.controllers || (app.controllers = {}));
44202         })(app || (app = {}));
44203         var app;
44204         (function (app) {
44205             var controllers;
44206             (function (controllers) {
44207                 var Preview = (function () {
44208                     function Preview($scope, APIEndPoint, $modalInstance) {
44209                         this.APIEndPoint = APIEndPoint;
44210                         this.$modalInstance = $modalInstance;
44211                         var controller = this;
44212                         console.log('preview');
44213                     }
44214                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44215                     return Preview;
44216                 })();
44217                 controllers.Preview = Preview;
44218             })(controllers = app.controllers || (app.controllers = {}));
44219         })(app || (app = {}));
44220         var filters;
44221         (function (filters) {
44222             function Tag() {
44223                 return function (commands, tag) {
44224                     var result = [];
44225                     angular.forEach(commands, function (command) {
44226                         var flag = false;
44227                         angular.forEach(command.tags, function (value) {
44228                             if (tag === value)
44229                                 flag = true;
44230                         });
44231                         if (flag)
44232                             result.push(command);
44233                     });
44234                     return result;
44235                 };
44236             }
44237             filters.Tag = Tag;
44238         })(filters || (filters = {}));
44239         var app;
44240         (function (app) {
44241             'use strict';
44242             var appName = 'zephyr';
44243             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
44244             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
44245                 $urlRouterProvider.otherwise('/execution');
44246                 $locationProvider.html5Mode({
44247                     enabled: true,
44248                     requireBase: false
44249                 });
44250                 $stateProvider
44251                     .state('execution', {
44252                     url: '/execution',
44253                     templateUrl: 'templates/execution.html',
44254                     controller: 'executionController',
44255                     controllerAs: 'c'
44256                 })
44257                     .state('workspace', {
44258                     url: '/workspace',
44259                     templateUrl: 'templates/workspace.html',
44260                     controller: 'workspaceController',
44261                     controllerAs: 'c'
44262                 })
44263                     .state('history', {
44264                     url: '/history',
44265                     templateUrl: 'templates/history.html',
44266                     controller: 'historyController',
44267                     controllerAs: 'c'
44268                 });
44269             });
44270             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
44271             app.zephyr.service('MyModal', app.services.MyModal);
44272             app.zephyr.service('WebSocket', app.services.WebSocket);
44273             app.zephyr.filter('Tag', filters.Tag);
44274             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
44275             app.zephyr.controller('previewController', app.controllers.Preview);
44276             app.zephyr.controller('executionController', app.controllers.Execution);
44277             app.zephyr.controller('workspaceController', app.controllers.Workspace);
44278             app.zephyr.controller('historyController', app.controllers.History);
44279             app.zephyr.controller('commandController', app.directives.CommandController);
44280             app.zephyr.controller('optionController', app.directives.OptionController);
44281             app.zephyr.controller('directoryController', app.directives.DirectoryController);
44282             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
44283             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
44284             app.zephyr.directive('command', app.directives.Command.Factory());
44285             app.zephyr.directive('option', app.directives.Option.Factory());
44286             app.zephyr.directive('directory', app.directives.Directory.Factory());
44287         })(app || (app = {}));
44288
44289
44290 /***/ },
44291 /* 13 */
44292 /***/ function(module, exports) {
44293
44294         var app;
44295         (function (app) {
44296             var declares;
44297             (function (declares) {
44298                 var CommandInfo = (function () {
44299                     function CommandInfo(name) {
44300                         this.name = name;
44301                     }
44302                     return CommandInfo;
44303                 })();
44304                 declares.CommandInfo = CommandInfo;
44305             })(declares = app.declares || (app.declares = {}));
44306         })(app || (app = {}));
44307         var app;
44308         (function (app) {
44309             var services;
44310             (function (services) {
44311                 var APIEndPoint = (function () {
44312                     function APIEndPoint($resource, $http) {
44313                         this.$resource = $resource;
44314                         this.$http = $http;
44315                     }
44316                     APIEndPoint.prototype.resource = function (endPoint, data) {
44317                         var customAction = {
44318                             method: 'GET',
44319                             isArray: false
44320                         };
44321                         var execute = {
44322                             method: 'POST',
44323                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
44324                         };
44325                         return this.$resource(endPoint, {}, { execute: execute });
44326                     };
44327                     APIEndPoint.prototype.getOptionControlFile = function (command) {
44328                         var endPoint = '/api/v1/optionControlFile/' + command;
44329                         return this.resource(endPoint, {}).get();
44330                     };
44331                     APIEndPoint.prototype.getFiles = function (fileId) {
44332                         var endPoint = '/api/v1/workspace';
44333                         if (fileId) {
44334                             endPoint += '/' + fileId;
44335                         }
44336                         return this.resource(endPoint, {}).get();
44337                     };
44338                     APIEndPoint.prototype.getDirectories = function () {
44339                         var endPoint = '/api/v1/all/workspace/directory';
44340                         return this.resource(endPoint, {}).get();
44341                     };
44342                     APIEndPoint.prototype.getTags = function () {
44343                         var endPoint = '/api/v1/tagList';
44344                         return this.resource(endPoint, {}).get();
44345                     };
44346                     APIEndPoint.prototype.getCommands = function () {
44347                         var endPoint = '/api/v1/commandList';
44348                         return this.resource(endPoint, {}).get();
44349                     };
44350                     APIEndPoint.prototype.execute = function (data) {
44351                         var endPoint = '/api/v1/execution';
44352                         var fd = new FormData();
44353                         fd.append('data', data);
44354                         return this.$http.post(endPoint, fd, {
44355                             headers: { 'Content-Type': undefined },
44356                             transformRequest: angular.identity
44357                         });
44358                     };
44359                     APIEndPoint.prototype.debug = function () {
44360                         var endPoint = '/api/v1/debug';
44361                         return this.$http.get(endPoint);
44362                     };
44363                     APIEndPoint.prototype.help = function (command) {
44364                         var endPoint = '/api/v1/help/' + command;
44365                         return this.$http.get(endPoint);
44366                     };
44367                     return APIEndPoint;
44368                 })();
44369                 services.APIEndPoint = APIEndPoint;
44370             })(services = app.services || (app.services = {}));
44371         })(app || (app = {}));
44372         var app;
44373         (function (app) {
44374             var services;
44375             (function (services) {
44376                 var MyModal = (function () {
44377                     function MyModal($uibModal) {
44378                         this.$uibModal = $uibModal;
44379                         this.modalOption = {
44380                             backdrop: true,
44381                             controller: null,
44382                             templateUrl: null,
44383                             size: null
44384                         };
44385                     }
44386                     MyModal.prototype.open = function (modalName) {
44387                         if (modalName === 'SelectCommand') {
44388                             this.modalOption.templateUrl = 'templates/select-command.html';
44389                             this.modalOption.size = 'lg';
44390                         }
44391                         return this.$uibModal.open(this.modalOption);
44392                     };
44393                     MyModal.prototype.selectCommand = function () {
44394                         this.modalOption.templateUrl = 'templates/select-command.html';
44395                         this.modalOption.controller = 'selectCommandController';
44396                         this.modalOption.controllerAs = 'c';
44397                         this.modalOption.size = 'lg';
44398                         return this.$uibModal.open(this.modalOption);
44399                     };
44400                     MyModal.prototype.preview = function () {
44401                         this.modalOption.templateUrl = 'templates/preview.html';
44402                         this.modalOption.controller = 'previewController';
44403                         this.modalOption.controllerAs = 'c';
44404                         this.modalOption.size = 'lg';
44405                         return this.$uibModal.open(this.modalOption);
44406                     };
44407                     MyModal.$inject = ['$uibModal'];
44408                     return MyModal;
44409                 })();
44410                 services.MyModal = MyModal;
44411             })(services = app.services || (app.services = {}));
44412         })(app || (app = {}));
44413         var app;
44414         (function (app) {
44415             var services;
44416             (function (services) {
44417                 var WebSocket = (function () {
44418                     function WebSocket($rootScope) {
44419                         this.$rootScope = $rootScope;
44420                         this.socket = io.connect();
44421                     }
44422                     WebSocket.prototype.on = function (eventName, callback) {
44423                         var socket = this.socket;
44424                         var rootScope = this.$rootScope;
44425                         socket.on(eventName, function () {
44426                             var args = arguments;
44427                             rootScope.$apply(function () {
44428                                 callback.apply(socket, args);
44429                             });
44430                         });
44431                     };
44432                     WebSocket.prototype.emit = function (eventName, data, callback) {
44433                         var socket = this.socket;
44434                         var rootScope = this.$rootScope;
44435                         this.socket.emit(eventName, data, function () {
44436                             var args = arguments;
44437                             rootScope.$apply(function () {
44438                                 if (callback)
44439                                     callback.apply(socket, args);
44440                             });
44441                         });
44442                     };
44443                     return WebSocket;
44444                 })();
44445                 services.WebSocket = WebSocket;
44446             })(services = app.services || (app.services = {}));
44447         })(app || (app = {}));
44448         var app;
44449         (function (app) {
44450             var directives;
44451             (function (directives) {
44452                 var Command = (function () {
44453                     function Command() {
44454                         this.restrict = 'E';
44455                         this.replace = true;
44456                         this.scope = true;
44457                         this.controller = 'commandController';
44458                         this.controllerAs = 'ctrl';
44459                         this.bindToController = {
44460                             index: '=',
44461                             name: '=',
44462                             remove: '&',
44463                             list: '='
44464                         };
44465                         this.templateUrl = 'templates/command.html';
44466                     }
44467                     Command.Factory = function () {
44468                         var directive = function () {
44469                             return new Command();
44470                         };
44471                         directive.$inject = [];
44472                         return directive;
44473                     };
44474                     return Command;
44475                 })();
44476                 directives.Command = Command;
44477                 var CommandController = (function () {
44478                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
44479                         this.APIEndPoint = APIEndPoint;
44480                         this.$scope = $scope;
44481                         this.MyModal = MyModal;
44482                         this.WebSocket = WebSocket;
44483                         this.$window = $window;
44484                         this.$rootScope = $rootScope;
44485                         var controller = this;
44486                         this.APIEndPoint
44487                             .getOptionControlFile(this.name)
44488                             .$promise
44489                             .then(function (result) {
44490                             controller.options = result.info;
44491                         });
44492                         this.APIEndPoint
44493                             .getDirectories()
44494                             .$promise
44495                             .then(function (result) {
44496                             controller.dirs = result.info;
44497                         });
44498                         this.heading = "[" + this.index + "]: dcdFilePrint";
44499                         this.isOpen = true;
44500                         this.$scope.$on('close', function () {
44501                             controller.isOpen = false;
44502                         });
44503                         function guid() {
44504                             function s4() {
44505                                 return Math.floor((1 + Math.random()) * 0x10000)
44506                                     .toString(16)
44507                                     .substring(1);
44508                             }
44509                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
44510                                 s4() + '-' + s4() + s4() + s4();
44511                         }
44512                         var uuid = guid();
44513                     }
44514                     CommandController.prototype.submit = function () {
44515                         var opt = [];
44516                         angular.forEach(this.options, function (option) {
44517                             var obj = {
44518                                 name: option.option,
44519                                 arguments: []
44520                             };
44521                             angular.forEach(option.arg, function (arg) {
44522                                 if (arg.input) {
44523                                     if (typeof arg.input === 'object') {
44524                                         obj.arguments.push(arg.input.name);
44525                                     }
44526                                     else {
44527                                         obj.arguments.push(arg.input);
44528                                     }
44529                                 }
44530                             });
44531                             if (obj.arguments.length > 0) {
44532                                 opt.push(obj);
44533                             }
44534                         });
44535                         var execObj = {
44536                             command: this.name,
44537                             workspace: this.workspace.fileId,
44538                             options: opt
44539                         };
44540                         this.APIEndPoint
44541                             .execute(JSON.stringify(execObj))
44542                             .then(function (result) {
44543                             console.log(result);
44544                         });
44545                     };
44546                     CommandController.prototype.removeMySelf = function (index) {
44547                         this.$scope.$destroy();
44548                         this.remove()(index, this.list);
44549                     };
44550                     CommandController.prototype.reloadFiles = function () {
44551                         var _this = this;
44552                         var fileId = this.workspace.fileId;
44553                         this.APIEndPoint
44554                             .getFiles(fileId)
44555                             .$promise
44556                             .then(function (result) {
44557                             var status = result.status;
44558                             if (status === 'success') {
44559                                 _this.files = result.info;
44560                             }
44561                             else {
44562                                 console.log(result.message);
44563                             }
44564                         });
44565                     };
44566                     CommandController.prototype.debug = function () {
44567                         console.log(this.$rootScope);
44568                         var div = angular.element(this.$window.document).find("div");
44569                         var consoleTag;
44570                         var parametersTag;
44571                         angular.forEach(div, function (v) {
44572                             if (v.className === "panel-body console") {
44573                                 consoleTag = v;
44574                             }
44575                             else if (v.className === "row parameters-console") {
44576                                 parametersTag = v;
44577                             }
44578                         });
44579                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
44580                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
44581                         consoleTag.style.height = consoleHeight;
44582                         consoleTag.style.width = consoleWidth;
44583                     };
44584                     CommandController.prototype.help = function () {
44585                         this.APIEndPoint
44586                             .help(this.name)
44587                             .then(function (result) {
44588                             console.log(result);
44589                         });
44590                     };
44591                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
44592                     return CommandController;
44593                 })();
44594                 directives.CommandController = CommandController;
44595             })(directives = app.directives || (app.directives = {}));
44596         })(app || (app = {}));
44597         var app;
44598         (function (app) {
44599             var directives;
44600             (function (directives) {
44601                 var HeaderMenu = (function () {
44602                     function HeaderMenu() {
44603                         this.restrict = 'E';
44604                         this.replace = true;
44605                         this.templateUrl = 'templates/header-menu.html';
44606                         this.controller = 'HeaderMenuController';
44607                         this.controllerAs = 'hmc';
44608                         this.scope = true;
44609                     }
44610                     HeaderMenu.Factory = function () {
44611                         var directive = function () {
44612                             return new HeaderMenu();
44613                         };
44614                         return directive;
44615                     };
44616                     return HeaderMenu;
44617                 })();
44618                 directives.HeaderMenu = HeaderMenu;
44619                 var HeaderMenuController = (function () {
44620                     function HeaderMenuController($state) {
44621                         this.$state = $state;
44622                         this.isExecution = this.$state.current.name === 'execution';
44623                         this.isWorkspace = this.$state.current.name === 'workspace';
44624                         this.isHistory = this.$state.current.name === 'history';
44625                     }
44626                     HeaderMenuController.prototype.transit = function (state) {
44627                         this.$state.go(state);
44628                     };
44629                     HeaderMenuController.$inject = ['$state'];
44630                     return HeaderMenuController;
44631                 })();
44632                 directives.HeaderMenuController = HeaderMenuController;
44633             })(directives = app.directives || (app.directives = {}));
44634         })(app || (app = {}));
44635         var app;
44636         (function (app) {
44637             var directives;
44638             (function (directives) {
44639                 var Option = (function () {
44640                     function Option() {
44641                         this.restrict = 'E';
44642                         this.replace = true;
44643                         this.controller = 'optionController';
44644                         this.bindToController = {
44645                             info: '=',
44646                             files: '='
44647                         };
44648                         this.scope = true;
44649                         this.templateUrl = 'templates/option.html';
44650                         this.controllerAs = 'ctrl';
44651                     }
44652                     Option.Factory = function () {
44653                         var directive = function () {
44654                             return new Option();
44655                         };
44656                         directive.$inject = [];
44657                         return directive;
44658                     };
44659                     return Option;
44660                 })();
44661                 directives.Option = Option;
44662                 var OptionController = (function () {
44663                     function OptionController() {
44664                         var controller = this;
44665                         angular.forEach(controller.info.arg, function (arg) {
44666                             if (arg.initialValue) {
44667                                 if (arg.formType === 'number') {
44668                                     arg.input = parseInt(arg.initialValue);
44669                                 }
44670                                 else {
44671                                     arg.input = arg.initialValue;
44672                                 }
44673                             }
44674                         });
44675                     }
44676                     OptionController.$inject = [];
44677                     return OptionController;
44678                 })();
44679                 directives.OptionController = OptionController;
44680             })(directives = app.directives || (app.directives = {}));
44681         })(app || (app = {}));
44682         var app;
44683         (function (app) {
44684             var directives;
44685             (function (directives) {
44686                 var Directory = (function () {
44687                     function Directory() {
44688                         this.restrict = 'E';
44689                         this.replace = true;
44690                         this.controller = 'directoryController';
44691                         this.controllerAs = 'ctrl';
44692                         this.bindToController = {
44693                             info: '=',
44694                             add: '&',
44695                             list: '=',
44696                             files: '='
44697                         };
44698                         this.templateUrl = 'templates/directory.html';
44699                     }
44700                     Directory.Factory = function () {
44701                         var directive = function () {
44702                             return new Directory();
44703                         };
44704                         return directive;
44705                     };
44706                     return Directory;
44707                 })();
44708                 directives.Directory = Directory;
44709                 var DirectoryController = (function () {
44710                     function DirectoryController(APIEndPoint, $scope) {
44711                         this.APIEndPoint = APIEndPoint;
44712                         this.$scope = $scope;
44713                         var controller = this;
44714                         this.APIEndPoint
44715                             .getFiles(this.info.fileId)
44716                             .$promise
44717                             .then(function (result) {
44718                             if (result.status === 'success') {
44719                                 controller.files = result.info;
44720                                 angular.forEach(result.info, function (file) {
44721                                     if (file.fileType === '0') {
44722                                         var o = file;
44723                                         if (controller.info.path === '/') {
44724                                             o.path = '/' + file.name;
44725                                         }
44726                                         else {
44727                                             o.path = controller.info.path + '/' + file.name;
44728                                         }
44729                                         controller.add()(o, controller.list);
44730                                     }
44731                                 });
44732                             }
44733                             ;
44734                         });
44735                     }
44736                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
44737                     return DirectoryController;
44738                 })();
44739                 directives.DirectoryController = DirectoryController;
44740             })(directives = app.directives || (app.directives = {}));
44741         })(app || (app = {}));
44742         var app;
44743         (function (app) {
44744             var controllers;
44745             (function (controllers) {
44746                 var Execution = (function () {
44747                     function Execution(MyModal, $scope) {
44748                         this.MyModal = MyModal;
44749                         this.$scope = $scope;
44750                         this.commandInfoList = [];
44751                     }
44752                     ;
44753                     Execution.prototype.add = function () {
44754                         this.$scope.$broadcast('close');
44755                         var commandInfoList = this.commandInfoList;
44756                         var commandInstance = this.MyModal.selectCommand();
44757                         commandInstance
44758                             .result
44759                             .then(function (command) {
44760                             commandInfoList.push(new app.declares.CommandInfo(command));
44761                         });
44762                     };
44763                     Execution.prototype.open = function () {
44764                         var result = this.MyModal.open('SelectCommand');
44765                         console.log(result);
44766                     };
44767                     Execution.prototype.remove = function (index, list) {
44768                         list.splice(index, 1);
44769                     };
44770                     Execution.prototype.close = function () {
44771                         console.log("close");
44772                     };
44773                     Execution.$inject = ['MyModal', '$scope'];
44774                     return Execution;
44775                 })();
44776                 controllers.Execution = Execution;
44777             })(controllers = app.controllers || (app.controllers = {}));
44778         })(app || (app = {}));
44779         var app;
44780         (function (app) {
44781             var controllers;
44782             (function (controllers) {
44783                 var Workspace = (function () {
44784                     function Workspace($scope, APIEndPoint, MyModal) {
44785                         this.$scope = $scope;
44786                         this.APIEndPoint = APIEndPoint;
44787                         this.MyModal = MyModal;
44788                         this.directoryList = [];
44789                         var controller = this;
44790                         var directoryList = this.directoryList;
44791                         var o = {
44792                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
44793                             name: '',
44794                             parentId: '',
44795                             fileType: '',
44796                             createdAt: '',
44797                             updatedAt: '',
44798                             path: '/'
44799                         };
44800                         directoryList.push(o);
44801                     }
44802                     Workspace.prototype.addDirectory = function (info, directoryList) {
44803                         directoryList.push(info);
44804                     };
44805                     Workspace.prototype.debug = function () {
44806                         this.MyModal.preview();
44807                     };
44808                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
44809                     return Workspace;
44810                 })();
44811                 controllers.Workspace = Workspace;
44812             })(controllers = app.controllers || (app.controllers = {}));
44813         })(app || (app = {}));
44814         var app;
44815         (function (app) {
44816             var controllers;
44817             (function (controllers) {
44818                 var History = (function () {
44819                     function History($scope) {
44820                         this.page = "History";
44821                     }
44822                     History.$inject = ['$scope'];
44823                     return History;
44824                 })();
44825                 controllers.History = History;
44826             })(controllers = app.controllers || (app.controllers = {}));
44827         })(app || (app = {}));
44828         var app;
44829         (function (app) {
44830             var controllers;
44831             (function (controllers) {
44832                 var SelectCommand = (function () {
44833                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
44834                         this.APIEndPoint = APIEndPoint;
44835                         this.$modalInstance = $modalInstance;
44836                         var controller = this;
44837                         this.APIEndPoint
44838                             .getTags()
44839                             .$promise.then(function (result) {
44840                             controller.tags = result.info;
44841                         });
44842                         this.APIEndPoint
44843                             .getCommands()
44844                             .$promise.then(function (result) {
44845                             controller.commands = result.info;
44846                         });
44847                         this.currentTag = 'all';
44848                     }
44849                     SelectCommand.prototype.changeTag = function (tag) {
44850                         this.currentTag = tag;
44851                     };
44852                     SelectCommand.prototype.selectCommand = function (command) {
44853                         this.$modalInstance.close(command);
44854                     };
44855                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44856                     return SelectCommand;
44857                 })();
44858                 controllers.SelectCommand = SelectCommand;
44859             })(controllers = app.controllers || (app.controllers = {}));
44860         })(app || (app = {}));
44861         var app;
44862         (function (app) {
44863             var controllers;
44864             (function (controllers) {
44865                 var Preview = (function () {
44866                     function Preview($scope, APIEndPoint, $modalInstance) {
44867                         this.APIEndPoint = APIEndPoint;
44868                         this.$modalInstance = $modalInstance;
44869                         var controller = this;
44870                         console.log('preview');
44871                     }
44872                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44873                     return Preview;
44874                 })();
44875                 controllers.Preview = Preview;
44876             })(controllers = app.controllers || (app.controllers = {}));
44877         })(app || (app = {}));
44878         var filters;
44879         (function (filters) {
44880             function Tag() {
44881                 return function (commands, tag) {
44882                     var result = [];
44883                     angular.forEach(commands, function (command) {
44884                         var flag = false;
44885                         angular.forEach(command.tags, function (value) {
44886                             if (tag === value)
44887                                 flag = true;
44888                         });
44889                         if (flag)
44890                             result.push(command);
44891                     });
44892                     return result;
44893                 };
44894             }
44895             filters.Tag = Tag;
44896         })(filters || (filters = {}));
44897         var app;
44898         (function (app) {
44899             'use strict';
44900             var appName = 'zephyr';
44901             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
44902             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
44903                 $urlRouterProvider.otherwise('/execution');
44904                 $locationProvider.html5Mode({
44905                     enabled: true,
44906                     requireBase: false
44907                 });
44908                 $stateProvider
44909                     .state('execution', {
44910                     url: '/execution',
44911                     templateUrl: 'templates/execution.html',
44912                     controller: 'executionController',
44913                     controllerAs: 'c'
44914                 })
44915                     .state('workspace', {
44916                     url: '/workspace',
44917                     templateUrl: 'templates/workspace.html',
44918                     controller: 'workspaceController',
44919                     controllerAs: 'c'
44920                 })
44921                     .state('history', {
44922                     url: '/history',
44923                     templateUrl: 'templates/history.html',
44924                     controller: 'historyController',
44925                     controllerAs: 'c'
44926                 });
44927             });
44928             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
44929             app.zephyr.service('MyModal', app.services.MyModal);
44930             app.zephyr.service('WebSocket', app.services.WebSocket);
44931             app.zephyr.filter('Tag', filters.Tag);
44932             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
44933             app.zephyr.controller('previewController', app.controllers.Preview);
44934             app.zephyr.controller('executionController', app.controllers.Execution);
44935             app.zephyr.controller('workspaceController', app.controllers.Workspace);
44936             app.zephyr.controller('historyController', app.controllers.History);
44937             app.zephyr.controller('commandController', app.directives.CommandController);
44938             app.zephyr.controller('optionController', app.directives.OptionController);
44939             app.zephyr.controller('directoryController', app.directives.DirectoryController);
44940             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
44941             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
44942             app.zephyr.directive('command', app.directives.Command.Factory());
44943             app.zephyr.directive('option', app.directives.Option.Factory());
44944             app.zephyr.directive('directory', app.directives.Directory.Factory());
44945         })(app || (app = {}));
44946
44947
44948 /***/ },
44949 /* 14 */
44950 /***/ function(module, exports) {
44951
44952         var app;
44953         (function (app) {
44954             var declares;
44955             (function (declares) {
44956                 var CommandInfo = (function () {
44957                     function CommandInfo(name) {
44958                         this.name = name;
44959                     }
44960                     return CommandInfo;
44961                 })();
44962                 declares.CommandInfo = CommandInfo;
44963             })(declares = app.declares || (app.declares = {}));
44964         })(app || (app = {}));
44965         var app;
44966         (function (app) {
44967             var services;
44968             (function (services) {
44969                 var APIEndPoint = (function () {
44970                     function APIEndPoint($resource, $http) {
44971                         this.$resource = $resource;
44972                         this.$http = $http;
44973                     }
44974                     APIEndPoint.prototype.resource = function (endPoint, data) {
44975                         var customAction = {
44976                             method: 'GET',
44977                             isArray: false
44978                         };
44979                         var execute = {
44980                             method: 'POST',
44981                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
44982                         };
44983                         return this.$resource(endPoint, {}, { execute: execute });
44984                     };
44985                     APIEndPoint.prototype.getOptionControlFile = function (command) {
44986                         var endPoint = '/api/v1/optionControlFile/' + command;
44987                         return this.resource(endPoint, {}).get();
44988                     };
44989                     APIEndPoint.prototype.getFiles = function (fileId) {
44990                         var endPoint = '/api/v1/workspace';
44991                         if (fileId) {
44992                             endPoint += '/' + fileId;
44993                         }
44994                         return this.resource(endPoint, {}).get();
44995                     };
44996                     APIEndPoint.prototype.getDirectories = function () {
44997                         var endPoint = '/api/v1/all/workspace/directory';
44998                         return this.resource(endPoint, {}).get();
44999                     };
45000                     APIEndPoint.prototype.getTags = function () {
45001                         var endPoint = '/api/v1/tagList';
45002                         return this.resource(endPoint, {}).get();
45003                     };
45004                     APIEndPoint.prototype.getCommands = function () {
45005                         var endPoint = '/api/v1/commandList';
45006                         return this.resource(endPoint, {}).get();
45007                     };
45008                     APIEndPoint.prototype.execute = function (data) {
45009                         var endPoint = '/api/v1/execution';
45010                         var fd = new FormData();
45011                         fd.append('data', data);
45012                         return this.$http.post(endPoint, fd, {
45013                             headers: { 'Content-Type': undefined },
45014                             transformRequest: angular.identity
45015                         });
45016                     };
45017                     APIEndPoint.prototype.debug = function () {
45018                         var endPoint = '/api/v1/debug';
45019                         return this.$http.get(endPoint);
45020                     };
45021                     APIEndPoint.prototype.help = function (command) {
45022                         var endPoint = '/api/v1/help/' + command;
45023                         return this.$http.get(endPoint);
45024                     };
45025                     return APIEndPoint;
45026                 })();
45027                 services.APIEndPoint = APIEndPoint;
45028             })(services = app.services || (app.services = {}));
45029         })(app || (app = {}));
45030         var app;
45031         (function (app) {
45032             var services;
45033             (function (services) {
45034                 var MyModal = (function () {
45035                     function MyModal($uibModal) {
45036                         this.$uibModal = $uibModal;
45037                         this.modalOption = {
45038                             backdrop: true,
45039                             controller: null,
45040                             templateUrl: null,
45041                             size: null
45042                         };
45043                     }
45044                     MyModal.prototype.open = function (modalName) {
45045                         if (modalName === 'SelectCommand') {
45046                             this.modalOption.templateUrl = 'templates/select-command.html';
45047                             this.modalOption.size = 'lg';
45048                         }
45049                         return this.$uibModal.open(this.modalOption);
45050                     };
45051                     MyModal.prototype.selectCommand = function () {
45052                         this.modalOption.templateUrl = 'templates/select-command.html';
45053                         this.modalOption.controller = 'selectCommandController';
45054                         this.modalOption.controllerAs = 'c';
45055                         this.modalOption.size = 'lg';
45056                         return this.$uibModal.open(this.modalOption);
45057                     };
45058                     MyModal.prototype.preview = function () {
45059                         this.modalOption.templateUrl = 'templates/preview.html';
45060                         this.modalOption.controller = 'previewController';
45061                         this.modalOption.controllerAs = 'c';
45062                         this.modalOption.size = 'lg';
45063                         return this.$uibModal.open(this.modalOption);
45064                     };
45065                     MyModal.$inject = ['$uibModal'];
45066                     return MyModal;
45067                 })();
45068                 services.MyModal = MyModal;
45069             })(services = app.services || (app.services = {}));
45070         })(app || (app = {}));
45071         var app;
45072         (function (app) {
45073             var services;
45074             (function (services) {
45075                 var WebSocket = (function () {
45076                     function WebSocket($rootScope) {
45077                         this.$rootScope = $rootScope;
45078                         this.socket = io.connect();
45079                     }
45080                     WebSocket.prototype.on = function (eventName, callback) {
45081                         var socket = this.socket;
45082                         var rootScope = this.$rootScope;
45083                         socket.on(eventName, function () {
45084                             var args = arguments;
45085                             rootScope.$apply(function () {
45086                                 callback.apply(socket, args);
45087                             });
45088                         });
45089                     };
45090                     WebSocket.prototype.emit = function (eventName, data, callback) {
45091                         var socket = this.socket;
45092                         var rootScope = this.$rootScope;
45093                         this.socket.emit(eventName, data, function () {
45094                             var args = arguments;
45095                             rootScope.$apply(function () {
45096                                 if (callback)
45097                                     callback.apply(socket, args);
45098                             });
45099                         });
45100                     };
45101                     return WebSocket;
45102                 })();
45103                 services.WebSocket = WebSocket;
45104             })(services = app.services || (app.services = {}));
45105         })(app || (app = {}));
45106         var app;
45107         (function (app) {
45108             var directives;
45109             (function (directives) {
45110                 var Command = (function () {
45111                     function Command() {
45112                         this.restrict = 'E';
45113                         this.replace = true;
45114                         this.scope = true;
45115                         this.controller = 'commandController';
45116                         this.controllerAs = 'ctrl';
45117                         this.bindToController = {
45118                             index: '=',
45119                             name: '=',
45120                             remove: '&',
45121                             list: '='
45122                         };
45123                         this.templateUrl = 'templates/command.html';
45124                     }
45125                     Command.Factory = function () {
45126                         var directive = function () {
45127                             return new Command();
45128                         };
45129                         directive.$inject = [];
45130                         return directive;
45131                     };
45132                     return Command;
45133                 })();
45134                 directives.Command = Command;
45135                 var CommandController = (function () {
45136                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
45137                         this.APIEndPoint = APIEndPoint;
45138                         this.$scope = $scope;
45139                         this.MyModal = MyModal;
45140                         this.WebSocket = WebSocket;
45141                         this.$window = $window;
45142                         this.$rootScope = $rootScope;
45143                         var controller = this;
45144                         this.APIEndPoint
45145                             .getOptionControlFile(this.name)
45146                             .$promise
45147                             .then(function (result) {
45148                             controller.options = result.info;
45149                         });
45150                         this.APIEndPoint
45151                             .getDirectories()
45152                             .$promise
45153                             .then(function (result) {
45154                             controller.dirs = result.info;
45155                         });
45156                         this.heading = "[" + this.index + "]: dcdFilePrint";
45157                         this.isOpen = true;
45158                         this.$scope.$on('close', function () {
45159                             controller.isOpen = false;
45160                         });
45161                         function guid() {
45162                             function s4() {
45163                                 return Math.floor((1 + Math.random()) * 0x10000)
45164                                     .toString(16)
45165                                     .substring(1);
45166                             }
45167                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
45168                                 s4() + '-' + s4() + s4() + s4();
45169                         }
45170                         var uuid = guid();
45171                     }
45172                     CommandController.prototype.submit = function () {
45173                         var opt = [];
45174                         angular.forEach(this.options, function (option) {
45175                             var obj = {
45176                                 name: option.option,
45177                                 arguments: []
45178                             };
45179                             angular.forEach(option.arg, function (arg) {
45180                                 if (arg.input) {
45181                                     if (typeof arg.input === 'object') {
45182                                         obj.arguments.push(arg.input.name);
45183                                     }
45184                                     else {
45185                                         obj.arguments.push(arg.input);
45186                                     }
45187                                 }
45188                             });
45189                             if (obj.arguments.length > 0) {
45190                                 opt.push(obj);
45191                             }
45192                         });
45193                         var execObj = {
45194                             command: this.name,
45195                             workspace: this.workspace.fileId,
45196                             options: opt
45197                         };
45198                         this.APIEndPoint
45199                             .execute(JSON.stringify(execObj))
45200                             .then(function (result) {
45201                             console.log(result);
45202                         });
45203                     };
45204                     CommandController.prototype.removeMySelf = function (index) {
45205                         this.$scope.$destroy();
45206                         this.remove()(index, this.list);
45207                     };
45208                     CommandController.prototype.reloadFiles = function () {
45209                         var _this = this;
45210                         var fileId = this.workspace.fileId;
45211                         this.APIEndPoint
45212                             .getFiles(fileId)
45213                             .$promise
45214                             .then(function (result) {
45215                             var status = result.status;
45216                             if (status === 'success') {
45217                                 _this.files = result.info;
45218                             }
45219                             else {
45220                                 console.log(result.message);
45221                             }
45222                         });
45223                     };
45224                     CommandController.prototype.debug = function () {
45225                         console.log(this.$rootScope);
45226                         var div = angular.element(this.$window.document).find("div");
45227                         var consoleTag;
45228                         var parametersTag;
45229                         angular.forEach(div, function (v) {
45230                             if (v.className === "panel-body console") {
45231                                 consoleTag = v;
45232                             }
45233                             else if (v.className === "row parameters-console") {
45234                                 parametersTag = v;
45235                             }
45236                         });
45237                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
45238                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
45239                         consoleTag.style.height = consoleHeight;
45240                         consoleTag.style.width = consoleWidth;
45241                     };
45242                     CommandController.prototype.help = function () {
45243                         this.APIEndPoint
45244                             .help(this.name)
45245                             .then(function (result) {
45246                             console.log(result);
45247                         });
45248                     };
45249                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
45250                     return CommandController;
45251                 })();
45252                 directives.CommandController = CommandController;
45253             })(directives = app.directives || (app.directives = {}));
45254         })(app || (app = {}));
45255         var app;
45256         (function (app) {
45257             var directives;
45258             (function (directives) {
45259                 var HeaderMenu = (function () {
45260                     function HeaderMenu() {
45261                         this.restrict = 'E';
45262                         this.replace = true;
45263                         this.templateUrl = 'templates/header-menu.html';
45264                         this.controller = 'HeaderMenuController';
45265                         this.controllerAs = 'hmc';
45266                         this.scope = true;
45267                     }
45268                     HeaderMenu.Factory = function () {
45269                         var directive = function () {
45270                             return new HeaderMenu();
45271                         };
45272                         return directive;
45273                     };
45274                     return HeaderMenu;
45275                 })();
45276                 directives.HeaderMenu = HeaderMenu;
45277                 var HeaderMenuController = (function () {
45278                     function HeaderMenuController($state) {
45279                         this.$state = $state;
45280                         this.isExecution = this.$state.current.name === 'execution';
45281                         this.isWorkspace = this.$state.current.name === 'workspace';
45282                         this.isHistory = this.$state.current.name === 'history';
45283                     }
45284                     HeaderMenuController.prototype.transit = function (state) {
45285                         this.$state.go(state);
45286                     };
45287                     HeaderMenuController.$inject = ['$state'];
45288                     return HeaderMenuController;
45289                 })();
45290                 directives.HeaderMenuController = HeaderMenuController;
45291             })(directives = app.directives || (app.directives = {}));
45292         })(app || (app = {}));
45293         var app;
45294         (function (app) {
45295             var directives;
45296             (function (directives) {
45297                 var Option = (function () {
45298                     function Option() {
45299                         this.restrict = 'E';
45300                         this.replace = true;
45301                         this.controller = 'optionController';
45302                         this.bindToController = {
45303                             info: '=',
45304                             files: '='
45305                         };
45306                         this.scope = true;
45307                         this.templateUrl = 'templates/option.html';
45308                         this.controllerAs = 'ctrl';
45309                     }
45310                     Option.Factory = function () {
45311                         var directive = function () {
45312                             return new Option();
45313                         };
45314                         directive.$inject = [];
45315                         return directive;
45316                     };
45317                     return Option;
45318                 })();
45319                 directives.Option = Option;
45320                 var OptionController = (function () {
45321                     function OptionController() {
45322                         var controller = this;
45323                         angular.forEach(controller.info.arg, function (arg) {
45324                             if (arg.initialValue) {
45325                                 if (arg.formType === 'number') {
45326                                     arg.input = parseInt(arg.initialValue);
45327                                 }
45328                                 else {
45329                                     arg.input = arg.initialValue;
45330                                 }
45331                             }
45332                         });
45333                     }
45334                     OptionController.$inject = [];
45335                     return OptionController;
45336                 })();
45337                 directives.OptionController = OptionController;
45338             })(directives = app.directives || (app.directives = {}));
45339         })(app || (app = {}));
45340         var app;
45341         (function (app) {
45342             var directives;
45343             (function (directives) {
45344                 var Directory = (function () {
45345                     function Directory() {
45346                         this.restrict = 'E';
45347                         this.replace = true;
45348                         this.controller = 'directoryController';
45349                         this.controllerAs = 'ctrl';
45350                         this.bindToController = {
45351                             info: '=',
45352                             add: '&',
45353                             list: '=',
45354                             files: '='
45355                         };
45356                         this.templateUrl = 'templates/directory.html';
45357                     }
45358                     Directory.Factory = function () {
45359                         var directive = function () {
45360                             return new Directory();
45361                         };
45362                         return directive;
45363                     };
45364                     return Directory;
45365                 })();
45366                 directives.Directory = Directory;
45367                 var DirectoryController = (function () {
45368                     function DirectoryController(APIEndPoint, $scope) {
45369                         this.APIEndPoint = APIEndPoint;
45370                         this.$scope = $scope;
45371                         var controller = this;
45372                         this.APIEndPoint
45373                             .getFiles(this.info.fileId)
45374                             .$promise
45375                             .then(function (result) {
45376                             if (result.status === 'success') {
45377                                 controller.files = result.info;
45378                                 angular.forEach(result.info, function (file) {
45379                                     if (file.fileType === '0') {
45380                                         var o = file;
45381                                         if (controller.info.path === '/') {
45382                                             o.path = '/' + file.name;
45383                                         }
45384                                         else {
45385                                             o.path = controller.info.path + '/' + file.name;
45386                                         }
45387                                         controller.add()(o, controller.list);
45388                                     }
45389                                 });
45390                             }
45391                             ;
45392                         });
45393                     }
45394                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
45395                     return DirectoryController;
45396                 })();
45397                 directives.DirectoryController = DirectoryController;
45398             })(directives = app.directives || (app.directives = {}));
45399         })(app || (app = {}));
45400         var app;
45401         (function (app) {
45402             var controllers;
45403             (function (controllers) {
45404                 var Execution = (function () {
45405                     function Execution(MyModal, $scope) {
45406                         this.MyModal = MyModal;
45407                         this.$scope = $scope;
45408                         this.commandInfoList = [];
45409                     }
45410                     ;
45411                     Execution.prototype.add = function () {
45412                         this.$scope.$broadcast('close');
45413                         var commandInfoList = this.commandInfoList;
45414                         var commandInstance = this.MyModal.selectCommand();
45415                         commandInstance
45416                             .result
45417                             .then(function (command) {
45418                             commandInfoList.push(new app.declares.CommandInfo(command));
45419                         });
45420                     };
45421                     Execution.prototype.open = function () {
45422                         var result = this.MyModal.open('SelectCommand');
45423                         console.log(result);
45424                     };
45425                     Execution.prototype.remove = function (index, list) {
45426                         list.splice(index, 1);
45427                     };
45428                     Execution.prototype.close = function () {
45429                         console.log("close");
45430                     };
45431                     Execution.$inject = ['MyModal', '$scope'];
45432                     return Execution;
45433                 })();
45434                 controllers.Execution = Execution;
45435             })(controllers = app.controllers || (app.controllers = {}));
45436         })(app || (app = {}));
45437         var app;
45438         (function (app) {
45439             var controllers;
45440             (function (controllers) {
45441                 var Workspace = (function () {
45442                     function Workspace($scope, APIEndPoint, MyModal) {
45443                         this.$scope = $scope;
45444                         this.APIEndPoint = APIEndPoint;
45445                         this.MyModal = MyModal;
45446                         this.directoryList = [];
45447                         var controller = this;
45448                         var directoryList = this.directoryList;
45449                         var o = {
45450                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
45451                             name: '',
45452                             parentId: '',
45453                             fileType: '',
45454                             createdAt: '',
45455                             updatedAt: '',
45456                             path: '/'
45457                         };
45458                         directoryList.push(o);
45459                     }
45460                     Workspace.prototype.addDirectory = function (info, directoryList) {
45461                         directoryList.push(info);
45462                     };
45463                     Workspace.prototype.debug = function () {
45464                         this.MyModal.preview();
45465                     };
45466                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
45467                     return Workspace;
45468                 })();
45469                 controllers.Workspace = Workspace;
45470             })(controllers = app.controllers || (app.controllers = {}));
45471         })(app || (app = {}));
45472         var app;
45473         (function (app) {
45474             var controllers;
45475             (function (controllers) {
45476                 var History = (function () {
45477                     function History($scope) {
45478                         this.page = "History";
45479                     }
45480                     History.$inject = ['$scope'];
45481                     return History;
45482                 })();
45483                 controllers.History = History;
45484             })(controllers = app.controllers || (app.controllers = {}));
45485         })(app || (app = {}));
45486         var app;
45487         (function (app) {
45488             var controllers;
45489             (function (controllers) {
45490                 var SelectCommand = (function () {
45491                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
45492                         this.APIEndPoint = APIEndPoint;
45493                         this.$modalInstance = $modalInstance;
45494                         var controller = this;
45495                         this.APIEndPoint
45496                             .getTags()
45497                             .$promise.then(function (result) {
45498                             controller.tags = result.info;
45499                         });
45500                         this.APIEndPoint
45501                             .getCommands()
45502                             .$promise.then(function (result) {
45503                             controller.commands = result.info;
45504                         });
45505                         this.currentTag = 'all';
45506                     }
45507                     SelectCommand.prototype.changeTag = function (tag) {
45508                         this.currentTag = tag;
45509                     };
45510                     SelectCommand.prototype.selectCommand = function (command) {
45511                         this.$modalInstance.close(command);
45512                     };
45513                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45514                     return SelectCommand;
45515                 })();
45516                 controllers.SelectCommand = SelectCommand;
45517             })(controllers = app.controllers || (app.controllers = {}));
45518         })(app || (app = {}));
45519         var app;
45520         (function (app) {
45521             var controllers;
45522             (function (controllers) {
45523                 var Preview = (function () {
45524                     function Preview($scope, APIEndPoint, $modalInstance) {
45525                         this.APIEndPoint = APIEndPoint;
45526                         this.$modalInstance = $modalInstance;
45527                         var controller = this;
45528                         console.log('preview');
45529                     }
45530                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45531                     return Preview;
45532                 })();
45533                 controllers.Preview = Preview;
45534             })(controllers = app.controllers || (app.controllers = {}));
45535         })(app || (app = {}));
45536         var filters;
45537         (function (filters) {
45538             function Tag() {
45539                 return function (commands, tag) {
45540                     var result = [];
45541                     angular.forEach(commands, function (command) {
45542                         var flag = false;
45543                         angular.forEach(command.tags, function (value) {
45544                             if (tag === value)
45545                                 flag = true;
45546                         });
45547                         if (flag)
45548                             result.push(command);
45549                     });
45550                     return result;
45551                 };
45552             }
45553             filters.Tag = Tag;
45554         })(filters || (filters = {}));
45555         var app;
45556         (function (app) {
45557             'use strict';
45558             var appName = 'zephyr';
45559             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
45560             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
45561                 $urlRouterProvider.otherwise('/execution');
45562                 $locationProvider.html5Mode({
45563                     enabled: true,
45564                     requireBase: false
45565                 });
45566                 $stateProvider
45567                     .state('execution', {
45568                     url: '/execution',
45569                     templateUrl: 'templates/execution.html',
45570                     controller: 'executionController',
45571                     controllerAs: 'c'
45572                 })
45573                     .state('workspace', {
45574                     url: '/workspace',
45575                     templateUrl: 'templates/workspace.html',
45576                     controller: 'workspaceController',
45577                     controllerAs: 'c'
45578                 })
45579                     .state('history', {
45580                     url: '/history',
45581                     templateUrl: 'templates/history.html',
45582                     controller: 'historyController',
45583                     controllerAs: 'c'
45584                 });
45585             });
45586             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
45587             app.zephyr.service('MyModal', app.services.MyModal);
45588             app.zephyr.service('WebSocket', app.services.WebSocket);
45589             app.zephyr.filter('Tag', filters.Tag);
45590             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
45591             app.zephyr.controller('previewController', app.controllers.Preview);
45592             app.zephyr.controller('executionController', app.controllers.Execution);
45593             app.zephyr.controller('workspaceController', app.controllers.Workspace);
45594             app.zephyr.controller('historyController', app.controllers.History);
45595             app.zephyr.controller('commandController', app.directives.CommandController);
45596             app.zephyr.controller('optionController', app.directives.OptionController);
45597             app.zephyr.controller('directoryController', app.directives.DirectoryController);
45598             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
45599             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
45600             app.zephyr.directive('command', app.directives.Command.Factory());
45601             app.zephyr.directive('option', app.directives.Option.Factory());
45602             app.zephyr.directive('directory', app.directives.Directory.Factory());
45603         })(app || (app = {}));
45604
45605
45606 /***/ },
45607 /* 15 */
45608 /***/ function(module, exports) {
45609
45610         var app;
45611         (function (app) {
45612             var declares;
45613             (function (declares) {
45614                 var CommandInfo = (function () {
45615                     function CommandInfo(name) {
45616                         this.name = name;
45617                     }
45618                     return CommandInfo;
45619                 })();
45620                 declares.CommandInfo = CommandInfo;
45621             })(declares = app.declares || (app.declares = {}));
45622         })(app || (app = {}));
45623         var app;
45624         (function (app) {
45625             var services;
45626             (function (services) {
45627                 var APIEndPoint = (function () {
45628                     function APIEndPoint($resource, $http) {
45629                         this.$resource = $resource;
45630                         this.$http = $http;
45631                     }
45632                     APIEndPoint.prototype.resource = function (endPoint, data) {
45633                         var customAction = {
45634                             method: 'GET',
45635                             isArray: false
45636                         };
45637                         var execute = {
45638                             method: 'POST',
45639                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
45640                         };
45641                         return this.$resource(endPoint, {}, { execute: execute });
45642                     };
45643                     APIEndPoint.prototype.getOptionControlFile = function (command) {
45644                         var endPoint = '/api/v1/optionControlFile/' + command;
45645                         return this.resource(endPoint, {}).get();
45646                     };
45647                     APIEndPoint.prototype.getFiles = function (fileId) {
45648                         var endPoint = '/api/v1/workspace';
45649                         if (fileId) {
45650                             endPoint += '/' + fileId;
45651                         }
45652                         return this.resource(endPoint, {}).get();
45653                     };
45654                     APIEndPoint.prototype.getDirectories = function () {
45655                         var endPoint = '/api/v1/all/workspace/directory';
45656                         return this.resource(endPoint, {}).get();
45657                     };
45658                     APIEndPoint.prototype.getTags = function () {
45659                         var endPoint = '/api/v1/tagList';
45660                         return this.resource(endPoint, {}).get();
45661                     };
45662                     APIEndPoint.prototype.getCommands = function () {
45663                         var endPoint = '/api/v1/commandList';
45664                         return this.resource(endPoint, {}).get();
45665                     };
45666                     APIEndPoint.prototype.execute = function (data) {
45667                         var endPoint = '/api/v1/execution';
45668                         var fd = new FormData();
45669                         fd.append('data', data);
45670                         return this.$http.post(endPoint, fd, {
45671                             headers: { 'Content-Type': undefined },
45672                             transformRequest: angular.identity
45673                         });
45674                     };
45675                     APIEndPoint.prototype.debug = function () {
45676                         var endPoint = '/api/v1/debug';
45677                         return this.$http.get(endPoint);
45678                     };
45679                     APIEndPoint.prototype.help = function (command) {
45680                         var endPoint = '/api/v1/help/' + command;
45681                         return this.$http.get(endPoint);
45682                     };
45683                     return APIEndPoint;
45684                 })();
45685                 services.APIEndPoint = APIEndPoint;
45686             })(services = app.services || (app.services = {}));
45687         })(app || (app = {}));
45688         var app;
45689         (function (app) {
45690             var services;
45691             (function (services) {
45692                 var MyModal = (function () {
45693                     function MyModal($uibModal) {
45694                         this.$uibModal = $uibModal;
45695                         this.modalOption = {
45696                             backdrop: true,
45697                             controller: null,
45698                             templateUrl: null,
45699                             size: null
45700                         };
45701                     }
45702                     MyModal.prototype.open = function (modalName) {
45703                         if (modalName === 'SelectCommand') {
45704                             this.modalOption.templateUrl = 'templates/select-command.html';
45705                             this.modalOption.size = 'lg';
45706                         }
45707                         return this.$uibModal.open(this.modalOption);
45708                     };
45709                     MyModal.prototype.selectCommand = function () {
45710                         this.modalOption.templateUrl = 'templates/select-command.html';
45711                         this.modalOption.controller = 'selectCommandController';
45712                         this.modalOption.controllerAs = 'c';
45713                         this.modalOption.size = 'lg';
45714                         return this.$uibModal.open(this.modalOption);
45715                     };
45716                     MyModal.prototype.preview = function () {
45717                         this.modalOption.templateUrl = 'templates/preview.html';
45718                         this.modalOption.controller = 'previewController';
45719                         this.modalOption.controllerAs = 'c';
45720                         this.modalOption.size = 'lg';
45721                         return this.$uibModal.open(this.modalOption);
45722                     };
45723                     MyModal.$inject = ['$uibModal'];
45724                     return MyModal;
45725                 })();
45726                 services.MyModal = MyModal;
45727             })(services = app.services || (app.services = {}));
45728         })(app || (app = {}));
45729         var app;
45730         (function (app) {
45731             var services;
45732             (function (services) {
45733                 var WebSocket = (function () {
45734                     function WebSocket($rootScope) {
45735                         this.$rootScope = $rootScope;
45736                         this.socket = io.connect();
45737                     }
45738                     WebSocket.prototype.on = function (eventName, callback) {
45739                         var socket = this.socket;
45740                         var rootScope = this.$rootScope;
45741                         socket.on(eventName, function () {
45742                             var args = arguments;
45743                             rootScope.$apply(function () {
45744                                 callback.apply(socket, args);
45745                             });
45746                         });
45747                     };
45748                     WebSocket.prototype.emit = function (eventName, data, callback) {
45749                         var socket = this.socket;
45750                         var rootScope = this.$rootScope;
45751                         this.socket.emit(eventName, data, function () {
45752                             var args = arguments;
45753                             rootScope.$apply(function () {
45754                                 if (callback)
45755                                     callback.apply(socket, args);
45756                             });
45757                         });
45758                     };
45759                     return WebSocket;
45760                 })();
45761                 services.WebSocket = WebSocket;
45762             })(services = app.services || (app.services = {}));
45763         })(app || (app = {}));
45764         var app;
45765         (function (app) {
45766             var directives;
45767             (function (directives) {
45768                 var Command = (function () {
45769                     function Command() {
45770                         this.restrict = 'E';
45771                         this.replace = true;
45772                         this.scope = true;
45773                         this.controller = 'commandController';
45774                         this.controllerAs = 'ctrl';
45775                         this.bindToController = {
45776                             index: '=',
45777                             name: '=',
45778                             remove: '&',
45779                             list: '='
45780                         };
45781                         this.templateUrl = 'templates/command.html';
45782                     }
45783                     Command.Factory = function () {
45784                         var directive = function () {
45785                             return new Command();
45786                         };
45787                         directive.$inject = [];
45788                         return directive;
45789                     };
45790                     return Command;
45791                 })();
45792                 directives.Command = Command;
45793                 var CommandController = (function () {
45794                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
45795                         this.APIEndPoint = APIEndPoint;
45796                         this.$scope = $scope;
45797                         this.MyModal = MyModal;
45798                         this.WebSocket = WebSocket;
45799                         this.$window = $window;
45800                         this.$rootScope = $rootScope;
45801                         var controller = this;
45802                         this.APIEndPoint
45803                             .getOptionControlFile(this.name)
45804                             .$promise
45805                             .then(function (result) {
45806                             controller.options = result.info;
45807                         });
45808                         this.APIEndPoint
45809                             .getDirectories()
45810                             .$promise
45811                             .then(function (result) {
45812                             controller.dirs = result.info;
45813                         });
45814                         this.heading = "[" + this.index + "]: dcdFilePrint";
45815                         this.isOpen = true;
45816                         this.$scope.$on('close', function () {
45817                             controller.isOpen = false;
45818                         });
45819                         function guid() {
45820                             function s4() {
45821                                 return Math.floor((1 + Math.random()) * 0x10000)
45822                                     .toString(16)
45823                                     .substring(1);
45824                             }
45825                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
45826                                 s4() + '-' + s4() + s4() + s4();
45827                         }
45828                         var uuid = guid();
45829                     }
45830                     CommandController.prototype.submit = function () {
45831                         var opt = [];
45832                         angular.forEach(this.options, function (option) {
45833                             var obj = {
45834                                 name: option.option,
45835                                 arguments: []
45836                             };
45837                             angular.forEach(option.arg, function (arg) {
45838                                 if (arg.input) {
45839                                     if (typeof arg.input === 'object') {
45840                                         obj.arguments.push(arg.input.name);
45841                                     }
45842                                     else {
45843                                         obj.arguments.push(arg.input);
45844                                     }
45845                                 }
45846                             });
45847                             if (obj.arguments.length > 0) {
45848                                 opt.push(obj);
45849                             }
45850                         });
45851                         var execObj = {
45852                             command: this.name,
45853                             workspace: this.workspace.fileId,
45854                             options: opt
45855                         };
45856                         this.APIEndPoint
45857                             .execute(JSON.stringify(execObj))
45858                             .then(function (result) {
45859                             console.log(result);
45860                         });
45861                     };
45862                     CommandController.prototype.removeMySelf = function (index) {
45863                         this.$scope.$destroy();
45864                         this.remove()(index, this.list);
45865                     };
45866                     CommandController.prototype.reloadFiles = function () {
45867                         var _this = this;
45868                         var fileId = this.workspace.fileId;
45869                         this.APIEndPoint
45870                             .getFiles(fileId)
45871                             .$promise
45872                             .then(function (result) {
45873                             var status = result.status;
45874                             if (status === 'success') {
45875                                 _this.files = result.info;
45876                             }
45877                             else {
45878                                 console.log(result.message);
45879                             }
45880                         });
45881                     };
45882                     CommandController.prototype.debug = function () {
45883                         console.log(this.$rootScope);
45884                         var div = angular.element(this.$window.document).find("div");
45885                         var consoleTag;
45886                         var parametersTag;
45887                         angular.forEach(div, function (v) {
45888                             if (v.className === "panel-body console") {
45889                                 consoleTag = v;
45890                             }
45891                             else if (v.className === "row parameters-console") {
45892                                 parametersTag = v;
45893                             }
45894                         });
45895                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
45896                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
45897                         consoleTag.style.height = consoleHeight;
45898                         consoleTag.style.width = consoleWidth;
45899                     };
45900                     CommandController.prototype.help = function () {
45901                         this.APIEndPoint
45902                             .help(this.name)
45903                             .then(function (result) {
45904                             console.log(result);
45905                         });
45906                     };
45907                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
45908                     return CommandController;
45909                 })();
45910                 directives.CommandController = CommandController;
45911             })(directives = app.directives || (app.directives = {}));
45912         })(app || (app = {}));
45913         var app;
45914         (function (app) {
45915             var directives;
45916             (function (directives) {
45917                 var HeaderMenu = (function () {
45918                     function HeaderMenu() {
45919                         this.restrict = 'E';
45920                         this.replace = true;
45921                         this.templateUrl = 'templates/header-menu.html';
45922                         this.controller = 'HeaderMenuController';
45923                         this.controllerAs = 'hmc';
45924                         this.scope = true;
45925                     }
45926                     HeaderMenu.Factory = function () {
45927                         var directive = function () {
45928                             return new HeaderMenu();
45929                         };
45930                         return directive;
45931                     };
45932                     return HeaderMenu;
45933                 })();
45934                 directives.HeaderMenu = HeaderMenu;
45935                 var HeaderMenuController = (function () {
45936                     function HeaderMenuController($state) {
45937                         this.$state = $state;
45938                         this.isExecution = this.$state.current.name === 'execution';
45939                         this.isWorkspace = this.$state.current.name === 'workspace';
45940                         this.isHistory = this.$state.current.name === 'history';
45941                     }
45942                     HeaderMenuController.prototype.transit = function (state) {
45943                         this.$state.go(state);
45944                     };
45945                     HeaderMenuController.$inject = ['$state'];
45946                     return HeaderMenuController;
45947                 })();
45948                 directives.HeaderMenuController = HeaderMenuController;
45949             })(directives = app.directives || (app.directives = {}));
45950         })(app || (app = {}));
45951         var app;
45952         (function (app) {
45953             var directives;
45954             (function (directives) {
45955                 var Option = (function () {
45956                     function Option() {
45957                         this.restrict = 'E';
45958                         this.replace = true;
45959                         this.controller = 'optionController';
45960                         this.bindToController = {
45961                             info: '=',
45962                             files: '='
45963                         };
45964                         this.scope = true;
45965                         this.templateUrl = 'templates/option.html';
45966                         this.controllerAs = 'ctrl';
45967                     }
45968                     Option.Factory = function () {
45969                         var directive = function () {
45970                             return new Option();
45971                         };
45972                         directive.$inject = [];
45973                         return directive;
45974                     };
45975                     return Option;
45976                 })();
45977                 directives.Option = Option;
45978                 var OptionController = (function () {
45979                     function OptionController() {
45980                         var controller = this;
45981                         angular.forEach(controller.info.arg, function (arg) {
45982                             if (arg.initialValue) {
45983                                 if (arg.formType === 'number') {
45984                                     arg.input = parseInt(arg.initialValue);
45985                                 }
45986                                 else {
45987                                     arg.input = arg.initialValue;
45988                                 }
45989                             }
45990                         });
45991                     }
45992                     OptionController.$inject = [];
45993                     return OptionController;
45994                 })();
45995                 directives.OptionController = OptionController;
45996             })(directives = app.directives || (app.directives = {}));
45997         })(app || (app = {}));
45998         var app;
45999         (function (app) {
46000             var directives;
46001             (function (directives) {
46002                 var Directory = (function () {
46003                     function Directory() {
46004                         this.restrict = 'E';
46005                         this.replace = true;
46006                         this.controller = 'directoryController';
46007                         this.controllerAs = 'ctrl';
46008                         this.bindToController = {
46009                             info: '=',
46010                             add: '&',
46011                             list: '=',
46012                             files: '='
46013                         };
46014                         this.templateUrl = 'templates/directory.html';
46015                     }
46016                     Directory.Factory = function () {
46017                         var directive = function () {
46018                             return new Directory();
46019                         };
46020                         return directive;
46021                     };
46022                     return Directory;
46023                 })();
46024                 directives.Directory = Directory;
46025                 var DirectoryController = (function () {
46026                     function DirectoryController(APIEndPoint, $scope) {
46027                         this.APIEndPoint = APIEndPoint;
46028                         this.$scope = $scope;
46029                         var controller = this;
46030                         this.APIEndPoint
46031                             .getFiles(this.info.fileId)
46032                             .$promise
46033                             .then(function (result) {
46034                             if (result.status === 'success') {
46035                                 controller.files = result.info;
46036                                 angular.forEach(result.info, function (file) {
46037                                     if (file.fileType === '0') {
46038                                         var o = file;
46039                                         if (controller.info.path === '/') {
46040                                             o.path = '/' + file.name;
46041                                         }
46042                                         else {
46043                                             o.path = controller.info.path + '/' + file.name;
46044                                         }
46045                                         controller.add()(o, controller.list);
46046                                     }
46047                                 });
46048                             }
46049                             ;
46050                         });
46051                     }
46052                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
46053                     return DirectoryController;
46054                 })();
46055                 directives.DirectoryController = DirectoryController;
46056             })(directives = app.directives || (app.directives = {}));
46057         })(app || (app = {}));
46058         var app;
46059         (function (app) {
46060             var controllers;
46061             (function (controllers) {
46062                 var Execution = (function () {
46063                     function Execution(MyModal, $scope) {
46064                         this.MyModal = MyModal;
46065                         this.$scope = $scope;
46066                         this.commandInfoList = [];
46067                     }
46068                     ;
46069                     Execution.prototype.add = function () {
46070                         this.$scope.$broadcast('close');
46071                         var commandInfoList = this.commandInfoList;
46072                         var commandInstance = this.MyModal.selectCommand();
46073                         commandInstance
46074                             .result
46075                             .then(function (command) {
46076                             commandInfoList.push(new app.declares.CommandInfo(command));
46077                         });
46078                     };
46079                     Execution.prototype.open = function () {
46080                         var result = this.MyModal.open('SelectCommand');
46081                         console.log(result);
46082                     };
46083                     Execution.prototype.remove = function (index, list) {
46084                         list.splice(index, 1);
46085                     };
46086                     Execution.prototype.close = function () {
46087                         console.log("close");
46088                     };
46089                     Execution.$inject = ['MyModal', '$scope'];
46090                     return Execution;
46091                 })();
46092                 controllers.Execution = Execution;
46093             })(controllers = app.controllers || (app.controllers = {}));
46094         })(app || (app = {}));
46095         var app;
46096         (function (app) {
46097             var controllers;
46098             (function (controllers) {
46099                 var Workspace = (function () {
46100                     function Workspace($scope, APIEndPoint, MyModal) {
46101                         this.$scope = $scope;
46102                         this.APIEndPoint = APIEndPoint;
46103                         this.MyModal = MyModal;
46104                         this.directoryList = [];
46105                         var controller = this;
46106                         var directoryList = this.directoryList;
46107                         var o = {
46108                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
46109                             name: '',
46110                             parentId: '',
46111                             fileType: '',
46112                             createdAt: '',
46113                             updatedAt: '',
46114                             path: '/'
46115                         };
46116                         directoryList.push(o);
46117                     }
46118                     Workspace.prototype.addDirectory = function (info, directoryList) {
46119                         directoryList.push(info);
46120                     };
46121                     Workspace.prototype.debug = function () {
46122                         this.MyModal.preview();
46123                     };
46124                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
46125                     return Workspace;
46126                 })();
46127                 controllers.Workspace = Workspace;
46128             })(controllers = app.controllers || (app.controllers = {}));
46129         })(app || (app = {}));
46130         var app;
46131         (function (app) {
46132             var controllers;
46133             (function (controllers) {
46134                 var History = (function () {
46135                     function History($scope) {
46136                         this.page = "History";
46137                     }
46138                     History.$inject = ['$scope'];
46139                     return History;
46140                 })();
46141                 controllers.History = History;
46142             })(controllers = app.controllers || (app.controllers = {}));
46143         })(app || (app = {}));
46144         var app;
46145         (function (app) {
46146             var controllers;
46147             (function (controllers) {
46148                 var SelectCommand = (function () {
46149                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
46150                         this.APIEndPoint = APIEndPoint;
46151                         this.$modalInstance = $modalInstance;
46152                         var controller = this;
46153                         this.APIEndPoint
46154                             .getTags()
46155                             .$promise.then(function (result) {
46156                             controller.tags = result.info;
46157                         });
46158                         this.APIEndPoint
46159                             .getCommands()
46160                             .$promise.then(function (result) {
46161                             controller.commands = result.info;
46162                         });
46163                         this.currentTag = 'all';
46164                     }
46165                     SelectCommand.prototype.changeTag = function (tag) {
46166                         this.currentTag = tag;
46167                     };
46168                     SelectCommand.prototype.selectCommand = function (command) {
46169                         this.$modalInstance.close(command);
46170                     };
46171                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46172                     return SelectCommand;
46173                 })();
46174                 controllers.SelectCommand = SelectCommand;
46175             })(controllers = app.controllers || (app.controllers = {}));
46176         })(app || (app = {}));
46177         var app;
46178         (function (app) {
46179             var controllers;
46180             (function (controllers) {
46181                 var Preview = (function () {
46182                     function Preview($scope, APIEndPoint, $modalInstance) {
46183                         this.APIEndPoint = APIEndPoint;
46184                         this.$modalInstance = $modalInstance;
46185                         var controller = this;
46186                         console.log('preview');
46187                     }
46188                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46189                     return Preview;
46190                 })();
46191                 controllers.Preview = Preview;
46192             })(controllers = app.controllers || (app.controllers = {}));
46193         })(app || (app = {}));
46194         var filters;
46195         (function (filters) {
46196             function Tag() {
46197                 return function (commands, tag) {
46198                     var result = [];
46199                     angular.forEach(commands, function (command) {
46200                         var flag = false;
46201                         angular.forEach(command.tags, function (value) {
46202                             if (tag === value)
46203                                 flag = true;
46204                         });
46205                         if (flag)
46206                             result.push(command);
46207                     });
46208                     return result;
46209                 };
46210             }
46211             filters.Tag = Tag;
46212         })(filters || (filters = {}));
46213         var app;
46214         (function (app) {
46215             'use strict';
46216             var appName = 'zephyr';
46217             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
46218             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
46219                 $urlRouterProvider.otherwise('/execution');
46220                 $locationProvider.html5Mode({
46221                     enabled: true,
46222                     requireBase: false
46223                 });
46224                 $stateProvider
46225                     .state('execution', {
46226                     url: '/execution',
46227                     templateUrl: 'templates/execution.html',
46228                     controller: 'executionController',
46229                     controllerAs: 'c'
46230                 })
46231                     .state('workspace', {
46232                     url: '/workspace',
46233                     templateUrl: 'templates/workspace.html',
46234                     controller: 'workspaceController',
46235                     controllerAs: 'c'
46236                 })
46237                     .state('history', {
46238                     url: '/history',
46239                     templateUrl: 'templates/history.html',
46240                     controller: 'historyController',
46241                     controllerAs: 'c'
46242                 });
46243             });
46244             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
46245             app.zephyr.service('MyModal', app.services.MyModal);
46246             app.zephyr.service('WebSocket', app.services.WebSocket);
46247             app.zephyr.filter('Tag', filters.Tag);
46248             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
46249             app.zephyr.controller('previewController', app.controllers.Preview);
46250             app.zephyr.controller('executionController', app.controllers.Execution);
46251             app.zephyr.controller('workspaceController', app.controllers.Workspace);
46252             app.zephyr.controller('historyController', app.controllers.History);
46253             app.zephyr.controller('commandController', app.directives.CommandController);
46254             app.zephyr.controller('optionController', app.directives.OptionController);
46255             app.zephyr.controller('directoryController', app.directives.DirectoryController);
46256             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
46257             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
46258             app.zephyr.directive('command', app.directives.Command.Factory());
46259             app.zephyr.directive('option', app.directives.Option.Factory());
46260             app.zephyr.directive('directory', app.directives.Directory.Factory());
46261         })(app || (app = {}));
46262
46263
46264 /***/ },
46265 /* 16 */
46266 /***/ function(module, exports) {
46267
46268         var app;
46269         (function (app) {
46270             var declares;
46271             (function (declares) {
46272                 var CommandInfo = (function () {
46273                     function CommandInfo(name) {
46274                         this.name = name;
46275                     }
46276                     return CommandInfo;
46277                 })();
46278                 declares.CommandInfo = CommandInfo;
46279             })(declares = app.declares || (app.declares = {}));
46280         })(app || (app = {}));
46281         var app;
46282         (function (app) {
46283             var services;
46284             (function (services) {
46285                 var APIEndPoint = (function () {
46286                     function APIEndPoint($resource, $http) {
46287                         this.$resource = $resource;
46288                         this.$http = $http;
46289                     }
46290                     APIEndPoint.prototype.resource = function (endPoint, data) {
46291                         var customAction = {
46292                             method: 'GET',
46293                             isArray: false
46294                         };
46295                         var execute = {
46296                             method: 'POST',
46297                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
46298                         };
46299                         return this.$resource(endPoint, {}, { execute: execute });
46300                     };
46301                     APIEndPoint.prototype.getOptionControlFile = function (command) {
46302                         var endPoint = '/api/v1/optionControlFile/' + command;
46303                         return this.resource(endPoint, {}).get();
46304                     };
46305                     APIEndPoint.prototype.getFiles = function (fileId) {
46306                         var endPoint = '/api/v1/workspace';
46307                         if (fileId) {
46308                             endPoint += '/' + fileId;
46309                         }
46310                         return this.resource(endPoint, {}).get();
46311                     };
46312                     APIEndPoint.prototype.getDirectories = function () {
46313                         var endPoint = '/api/v1/all/workspace/directory';
46314                         return this.resource(endPoint, {}).get();
46315                     };
46316                     APIEndPoint.prototype.getTags = function () {
46317                         var endPoint = '/api/v1/tagList';
46318                         return this.resource(endPoint, {}).get();
46319                     };
46320                     APIEndPoint.prototype.getCommands = function () {
46321                         var endPoint = '/api/v1/commandList';
46322                         return this.resource(endPoint, {}).get();
46323                     };
46324                     APIEndPoint.prototype.execute = function (data) {
46325                         var endPoint = '/api/v1/execution';
46326                         var fd = new FormData();
46327                         fd.append('data', data);
46328                         return this.$http.post(endPoint, fd, {
46329                             headers: { 'Content-Type': undefined },
46330                             transformRequest: angular.identity
46331                         });
46332                     };
46333                     APIEndPoint.prototype.debug = function () {
46334                         var endPoint = '/api/v1/debug';
46335                         return this.$http.get(endPoint);
46336                     };
46337                     APIEndPoint.prototype.help = function (command) {
46338                         var endPoint = '/api/v1/help/' + command;
46339                         return this.$http.get(endPoint);
46340                     };
46341                     return APIEndPoint;
46342                 })();
46343                 services.APIEndPoint = APIEndPoint;
46344             })(services = app.services || (app.services = {}));
46345         })(app || (app = {}));
46346         var app;
46347         (function (app) {
46348             var services;
46349             (function (services) {
46350                 var MyModal = (function () {
46351                     function MyModal($uibModal) {
46352                         this.$uibModal = $uibModal;
46353                         this.modalOption = {
46354                             backdrop: true,
46355                             controller: null,
46356                             templateUrl: null,
46357                             size: null
46358                         };
46359                     }
46360                     MyModal.prototype.open = function (modalName) {
46361                         if (modalName === 'SelectCommand') {
46362                             this.modalOption.templateUrl = 'templates/select-command.html';
46363                             this.modalOption.size = 'lg';
46364                         }
46365                         return this.$uibModal.open(this.modalOption);
46366                     };
46367                     MyModal.prototype.selectCommand = function () {
46368                         this.modalOption.templateUrl = 'templates/select-command.html';
46369                         this.modalOption.controller = 'selectCommandController';
46370                         this.modalOption.controllerAs = 'c';
46371                         this.modalOption.size = 'lg';
46372                         return this.$uibModal.open(this.modalOption);
46373                     };
46374                     MyModal.prototype.preview = function () {
46375                         this.modalOption.templateUrl = 'templates/preview.html';
46376                         this.modalOption.controller = 'previewController';
46377                         this.modalOption.controllerAs = 'c';
46378                         this.modalOption.size = 'lg';
46379                         return this.$uibModal.open(this.modalOption);
46380                     };
46381                     MyModal.$inject = ['$uibModal'];
46382                     return MyModal;
46383                 })();
46384                 services.MyModal = MyModal;
46385             })(services = app.services || (app.services = {}));
46386         })(app || (app = {}));
46387         var app;
46388         (function (app) {
46389             var services;
46390             (function (services) {
46391                 var WebSocket = (function () {
46392                     function WebSocket($rootScope) {
46393                         this.$rootScope = $rootScope;
46394                         this.socket = io.connect();
46395                     }
46396                     WebSocket.prototype.on = function (eventName, callback) {
46397                         var socket = this.socket;
46398                         var rootScope = this.$rootScope;
46399                         socket.on(eventName, function () {
46400                             var args = arguments;
46401                             rootScope.$apply(function () {
46402                                 callback.apply(socket, args);
46403                             });
46404                         });
46405                     };
46406                     WebSocket.prototype.emit = function (eventName, data, callback) {
46407                         var socket = this.socket;
46408                         var rootScope = this.$rootScope;
46409                         this.socket.emit(eventName, data, function () {
46410                             var args = arguments;
46411                             rootScope.$apply(function () {
46412                                 if (callback)
46413                                     callback.apply(socket, args);
46414                             });
46415                         });
46416                     };
46417                     return WebSocket;
46418                 })();
46419                 services.WebSocket = WebSocket;
46420             })(services = app.services || (app.services = {}));
46421         })(app || (app = {}));
46422         var app;
46423         (function (app) {
46424             var directives;
46425             (function (directives) {
46426                 var Command = (function () {
46427                     function Command() {
46428                         this.restrict = 'E';
46429                         this.replace = true;
46430                         this.scope = true;
46431                         this.controller = 'commandController';
46432                         this.controllerAs = 'ctrl';
46433                         this.bindToController = {
46434                             index: '=',
46435                             name: '=',
46436                             remove: '&',
46437                             list: '='
46438                         };
46439                         this.templateUrl = 'templates/command.html';
46440                     }
46441                     Command.Factory = function () {
46442                         var directive = function () {
46443                             return new Command();
46444                         };
46445                         directive.$inject = [];
46446                         return directive;
46447                     };
46448                     return Command;
46449                 })();
46450                 directives.Command = Command;
46451                 var CommandController = (function () {
46452                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
46453                         this.APIEndPoint = APIEndPoint;
46454                         this.$scope = $scope;
46455                         this.MyModal = MyModal;
46456                         this.WebSocket = WebSocket;
46457                         this.$window = $window;
46458                         this.$rootScope = $rootScope;
46459                         var controller = this;
46460                         this.APIEndPoint
46461                             .getOptionControlFile(this.name)
46462                             .$promise
46463                             .then(function (result) {
46464                             controller.options = result.info;
46465                         });
46466                         this.APIEndPoint
46467                             .getDirectories()
46468                             .$promise
46469                             .then(function (result) {
46470                             controller.dirs = result.info;
46471                         });
46472                         this.heading = "[" + this.index + "]: dcdFilePrint";
46473                         this.isOpen = true;
46474                         this.$scope.$on('close', function () {
46475                             controller.isOpen = false;
46476                         });
46477                         function guid() {
46478                             function s4() {
46479                                 return Math.floor((1 + Math.random()) * 0x10000)
46480                                     .toString(16)
46481                                     .substring(1);
46482                             }
46483                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
46484                                 s4() + '-' + s4() + s4() + s4();
46485                         }
46486                         var uuid = guid();
46487                     }
46488                     CommandController.prototype.submit = function () {
46489                         var opt = [];
46490                         angular.forEach(this.options, function (option) {
46491                             var obj = {
46492                                 name: option.option,
46493                                 arguments: []
46494                             };
46495                             angular.forEach(option.arg, function (arg) {
46496                                 if (arg.input) {
46497                                     if (typeof arg.input === 'object') {
46498                                         obj.arguments.push(arg.input.name);
46499                                     }
46500                                     else {
46501                                         obj.arguments.push(arg.input);
46502                                     }
46503                                 }
46504                             });
46505                             if (obj.arguments.length > 0) {
46506                                 opt.push(obj);
46507                             }
46508                         });
46509                         var execObj = {
46510                             command: this.name,
46511                             workspace: this.workspace.fileId,
46512                             options: opt
46513                         };
46514                         this.APIEndPoint
46515                             .execute(JSON.stringify(execObj))
46516                             .then(function (result) {
46517                             console.log(result);
46518                         });
46519                     };
46520                     CommandController.prototype.removeMySelf = function (index) {
46521                         this.$scope.$destroy();
46522                         this.remove()(index, this.list);
46523                     };
46524                     CommandController.prototype.reloadFiles = function () {
46525                         var _this = this;
46526                         var fileId = this.workspace.fileId;
46527                         this.APIEndPoint
46528                             .getFiles(fileId)
46529                             .$promise
46530                             .then(function (result) {
46531                             var status = result.status;
46532                             if (status === 'success') {
46533                                 _this.files = result.info;
46534                             }
46535                             else {
46536                                 console.log(result.message);
46537                             }
46538                         });
46539                     };
46540                     CommandController.prototype.debug = function () {
46541                         console.log(this.$rootScope);
46542                         var div = angular.element(this.$window.document).find("div");
46543                         var consoleTag;
46544                         var parametersTag;
46545                         angular.forEach(div, function (v) {
46546                             if (v.className === "panel-body console") {
46547                                 consoleTag = v;
46548                             }
46549                             else if (v.className === "row parameters-console") {
46550                                 parametersTag = v;
46551                             }
46552                         });
46553                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
46554                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
46555                         consoleTag.style.height = consoleHeight;
46556                         consoleTag.style.width = consoleWidth;
46557                     };
46558                     CommandController.prototype.help = function () {
46559                         this.APIEndPoint
46560                             .help(this.name)
46561                             .then(function (result) {
46562                             console.log(result);
46563                         });
46564                     };
46565                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
46566                     return CommandController;
46567                 })();
46568                 directives.CommandController = CommandController;
46569             })(directives = app.directives || (app.directives = {}));
46570         })(app || (app = {}));
46571         var app;
46572         (function (app) {
46573             var directives;
46574             (function (directives) {
46575                 var HeaderMenu = (function () {
46576                     function HeaderMenu() {
46577                         this.restrict = 'E';
46578                         this.replace = true;
46579                         this.templateUrl = 'templates/header-menu.html';
46580                         this.controller = 'HeaderMenuController';
46581                         this.controllerAs = 'hmc';
46582                         this.scope = true;
46583                     }
46584                     HeaderMenu.Factory = function () {
46585                         var directive = function () {
46586                             return new HeaderMenu();
46587                         };
46588                         return directive;
46589                     };
46590                     return HeaderMenu;
46591                 })();
46592                 directives.HeaderMenu = HeaderMenu;
46593                 var HeaderMenuController = (function () {
46594                     function HeaderMenuController($state) {
46595                         this.$state = $state;
46596                         this.isExecution = this.$state.current.name === 'execution';
46597                         this.isWorkspace = this.$state.current.name === 'workspace';
46598                         this.isHistory = this.$state.current.name === 'history';
46599                     }
46600                     HeaderMenuController.prototype.transit = function (state) {
46601                         this.$state.go(state);
46602                     };
46603                     HeaderMenuController.$inject = ['$state'];
46604                     return HeaderMenuController;
46605                 })();
46606                 directives.HeaderMenuController = HeaderMenuController;
46607             })(directives = app.directives || (app.directives = {}));
46608         })(app || (app = {}));
46609         var app;
46610         (function (app) {
46611             var directives;
46612             (function (directives) {
46613                 var Option = (function () {
46614                     function Option() {
46615                         this.restrict = 'E';
46616                         this.replace = true;
46617                         this.controller = 'optionController';
46618                         this.bindToController = {
46619                             info: '=',
46620                             files: '='
46621                         };
46622                         this.scope = true;
46623                         this.templateUrl = 'templates/option.html';
46624                         this.controllerAs = 'ctrl';
46625                     }
46626                     Option.Factory = function () {
46627                         var directive = function () {
46628                             return new Option();
46629                         };
46630                         directive.$inject = [];
46631                         return directive;
46632                     };
46633                     return Option;
46634                 })();
46635                 directives.Option = Option;
46636                 var OptionController = (function () {
46637                     function OptionController() {
46638                         var controller = this;
46639                         angular.forEach(controller.info.arg, function (arg) {
46640                             if (arg.initialValue) {
46641                                 if (arg.formType === 'number') {
46642                                     arg.input = parseInt(arg.initialValue);
46643                                 }
46644                                 else {
46645                                     arg.input = arg.initialValue;
46646                                 }
46647                             }
46648                         });
46649                     }
46650                     OptionController.$inject = [];
46651                     return OptionController;
46652                 })();
46653                 directives.OptionController = OptionController;
46654             })(directives = app.directives || (app.directives = {}));
46655         })(app || (app = {}));
46656         var app;
46657         (function (app) {
46658             var directives;
46659             (function (directives) {
46660                 var Directory = (function () {
46661                     function Directory() {
46662                         this.restrict = 'E';
46663                         this.replace = true;
46664                         this.controller = 'directoryController';
46665                         this.controllerAs = 'ctrl';
46666                         this.bindToController = {
46667                             info: '=',
46668                             add: '&',
46669                             list: '=',
46670                             files: '='
46671                         };
46672                         this.templateUrl = 'templates/directory.html';
46673                     }
46674                     Directory.Factory = function () {
46675                         var directive = function () {
46676                             return new Directory();
46677                         };
46678                         return directive;
46679                     };
46680                     return Directory;
46681                 })();
46682                 directives.Directory = Directory;
46683                 var DirectoryController = (function () {
46684                     function DirectoryController(APIEndPoint, $scope) {
46685                         this.APIEndPoint = APIEndPoint;
46686                         this.$scope = $scope;
46687                         var controller = this;
46688                         this.APIEndPoint
46689                             .getFiles(this.info.fileId)
46690                             .$promise
46691                             .then(function (result) {
46692                             if (result.status === 'success') {
46693                                 controller.files = result.info;
46694                                 angular.forEach(result.info, function (file) {
46695                                     if (file.fileType === '0') {
46696                                         var o = file;
46697                                         if (controller.info.path === '/') {
46698                                             o.path = '/' + file.name;
46699                                         }
46700                                         else {
46701                                             o.path = controller.info.path + '/' + file.name;
46702                                         }
46703                                         controller.add()(o, controller.list);
46704                                     }
46705                                 });
46706                             }
46707                             ;
46708                         });
46709                     }
46710                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
46711                     return DirectoryController;
46712                 })();
46713                 directives.DirectoryController = DirectoryController;
46714             })(directives = app.directives || (app.directives = {}));
46715         })(app || (app = {}));
46716         var app;
46717         (function (app) {
46718             var controllers;
46719             (function (controllers) {
46720                 var Execution = (function () {
46721                     function Execution(MyModal, $scope) {
46722                         this.MyModal = MyModal;
46723                         this.$scope = $scope;
46724                         this.commandInfoList = [];
46725                     }
46726                     ;
46727                     Execution.prototype.add = function () {
46728                         this.$scope.$broadcast('close');
46729                         var commandInfoList = this.commandInfoList;
46730                         var commandInstance = this.MyModal.selectCommand();
46731                         commandInstance
46732                             .result
46733                             .then(function (command) {
46734                             commandInfoList.push(new app.declares.CommandInfo(command));
46735                         });
46736                     };
46737                     Execution.prototype.open = function () {
46738                         var result = this.MyModal.open('SelectCommand');
46739                         console.log(result);
46740                     };
46741                     Execution.prototype.remove = function (index, list) {
46742                         list.splice(index, 1);
46743                     };
46744                     Execution.prototype.close = function () {
46745                         console.log("close");
46746                     };
46747                     Execution.$inject = ['MyModal', '$scope'];
46748                     return Execution;
46749                 })();
46750                 controllers.Execution = Execution;
46751             })(controllers = app.controllers || (app.controllers = {}));
46752         })(app || (app = {}));
46753         var app;
46754         (function (app) {
46755             var controllers;
46756             (function (controllers) {
46757                 var Workspace = (function () {
46758                     function Workspace($scope, APIEndPoint, MyModal) {
46759                         this.$scope = $scope;
46760                         this.APIEndPoint = APIEndPoint;
46761                         this.MyModal = MyModal;
46762                         this.directoryList = [];
46763                         var controller = this;
46764                         var directoryList = this.directoryList;
46765                         var o = {
46766                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
46767                             name: '',
46768                             parentId: '',
46769                             fileType: '',
46770                             createdAt: '',
46771                             updatedAt: '',
46772                             path: '/'
46773                         };
46774                         directoryList.push(o);
46775                     }
46776                     Workspace.prototype.addDirectory = function (info, directoryList) {
46777                         directoryList.push(info);
46778                     };
46779                     Workspace.prototype.debug = function () {
46780                         this.MyModal.preview();
46781                     };
46782                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
46783                     return Workspace;
46784                 })();
46785                 controllers.Workspace = Workspace;
46786             })(controllers = app.controllers || (app.controllers = {}));
46787         })(app || (app = {}));
46788         var app;
46789         (function (app) {
46790             var controllers;
46791             (function (controllers) {
46792                 var History = (function () {
46793                     function History($scope) {
46794                         this.page = "History";
46795                     }
46796                     History.$inject = ['$scope'];
46797                     return History;
46798                 })();
46799                 controllers.History = History;
46800             })(controllers = app.controllers || (app.controllers = {}));
46801         })(app || (app = {}));
46802         var app;
46803         (function (app) {
46804             var controllers;
46805             (function (controllers) {
46806                 var SelectCommand = (function () {
46807                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
46808                         this.APIEndPoint = APIEndPoint;
46809                         this.$modalInstance = $modalInstance;
46810                         var controller = this;
46811                         this.APIEndPoint
46812                             .getTags()
46813                             .$promise.then(function (result) {
46814                             controller.tags = result.info;
46815                         });
46816                         this.APIEndPoint
46817                             .getCommands()
46818                             .$promise.then(function (result) {
46819                             controller.commands = result.info;
46820                         });
46821                         this.currentTag = 'all';
46822                     }
46823                     SelectCommand.prototype.changeTag = function (tag) {
46824                         this.currentTag = tag;
46825                     };
46826                     SelectCommand.prototype.selectCommand = function (command) {
46827                         this.$modalInstance.close(command);
46828                     };
46829                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46830                     return SelectCommand;
46831                 })();
46832                 controllers.SelectCommand = SelectCommand;
46833             })(controllers = app.controllers || (app.controllers = {}));
46834         })(app || (app = {}));
46835         var app;
46836         (function (app) {
46837             var controllers;
46838             (function (controllers) {
46839                 var Preview = (function () {
46840                     function Preview($scope, APIEndPoint, $modalInstance) {
46841                         this.APIEndPoint = APIEndPoint;
46842                         this.$modalInstance = $modalInstance;
46843                         var controller = this;
46844                         console.log('preview');
46845                     }
46846                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46847                     return Preview;
46848                 })();
46849                 controllers.Preview = Preview;
46850             })(controllers = app.controllers || (app.controllers = {}));
46851         })(app || (app = {}));
46852         var filters;
46853         (function (filters) {
46854             function Tag() {
46855                 return function (commands, tag) {
46856                     var result = [];
46857                     angular.forEach(commands, function (command) {
46858                         var flag = false;
46859                         angular.forEach(command.tags, function (value) {
46860                             if (tag === value)
46861                                 flag = true;
46862                         });
46863                         if (flag)
46864                             result.push(command);
46865                     });
46866                     return result;
46867                 };
46868             }
46869             filters.Tag = Tag;
46870         })(filters || (filters = {}));
46871         var app;
46872         (function (app) {
46873             'use strict';
46874             var appName = 'zephyr';
46875             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
46876             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
46877                 $urlRouterProvider.otherwise('/execution');
46878                 $locationProvider.html5Mode({
46879                     enabled: true,
46880                     requireBase: false
46881                 });
46882                 $stateProvider
46883                     .state('execution', {
46884                     url: '/execution',
46885                     templateUrl: 'templates/execution.html',
46886                     controller: 'executionController',
46887                     controllerAs: 'c'
46888                 })
46889                     .state('workspace', {
46890                     url: '/workspace',
46891                     templateUrl: 'templates/workspace.html',
46892                     controller: 'workspaceController',
46893                     controllerAs: 'c'
46894                 })
46895                     .state('history', {
46896                     url: '/history',
46897                     templateUrl: 'templates/history.html',
46898                     controller: 'historyController',
46899                     controllerAs: 'c'
46900                 });
46901             });
46902             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
46903             app.zephyr.service('MyModal', app.services.MyModal);
46904             app.zephyr.service('WebSocket', app.services.WebSocket);
46905             app.zephyr.filter('Tag', filters.Tag);
46906             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
46907             app.zephyr.controller('previewController', app.controllers.Preview);
46908             app.zephyr.controller('executionController', app.controllers.Execution);
46909             app.zephyr.controller('workspaceController', app.controllers.Workspace);
46910             app.zephyr.controller('historyController', app.controllers.History);
46911             app.zephyr.controller('commandController', app.directives.CommandController);
46912             app.zephyr.controller('optionController', app.directives.OptionController);
46913             app.zephyr.controller('directoryController', app.directives.DirectoryController);
46914             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
46915             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
46916             app.zephyr.directive('command', app.directives.Command.Factory());
46917             app.zephyr.directive('option', app.directives.Option.Factory());
46918             app.zephyr.directive('directory', app.directives.Directory.Factory());
46919         })(app || (app = {}));
46920
46921
46922 /***/ },
46923 /* 17 */
46924 /***/ function(module, exports) {
46925
46926         var app;
46927         (function (app) {
46928             var declares;
46929             (function (declares) {
46930                 var CommandInfo = (function () {
46931                     function CommandInfo(name) {
46932                         this.name = name;
46933                     }
46934                     return CommandInfo;
46935                 })();
46936                 declares.CommandInfo = CommandInfo;
46937             })(declares = app.declares || (app.declares = {}));
46938         })(app || (app = {}));
46939         var app;
46940         (function (app) {
46941             var services;
46942             (function (services) {
46943                 var APIEndPoint = (function () {
46944                     function APIEndPoint($resource, $http) {
46945                         this.$resource = $resource;
46946                         this.$http = $http;
46947                     }
46948                     APIEndPoint.prototype.resource = function (endPoint, data) {
46949                         var customAction = {
46950                             method: 'GET',
46951                             isArray: false
46952                         };
46953                         var execute = {
46954                             method: 'POST',
46955                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
46956                         };
46957                         return this.$resource(endPoint, {}, { execute: execute });
46958                     };
46959                     APIEndPoint.prototype.getOptionControlFile = function (command) {
46960                         var endPoint = '/api/v1/optionControlFile/' + command;
46961                         return this.resource(endPoint, {}).get();
46962                     };
46963                     APIEndPoint.prototype.getFiles = function (fileId) {
46964                         var endPoint = '/api/v1/workspace';
46965                         if (fileId) {
46966                             endPoint += '/' + fileId;
46967                         }
46968                         return this.resource(endPoint, {}).get();
46969                     };
46970                     APIEndPoint.prototype.getDirectories = function () {
46971                         var endPoint = '/api/v1/all/workspace/directory';
46972                         return this.resource(endPoint, {}).get();
46973                     };
46974                     APIEndPoint.prototype.getTags = function () {
46975                         var endPoint = '/api/v1/tagList';
46976                         return this.resource(endPoint, {}).get();
46977                     };
46978                     APIEndPoint.prototype.getCommands = function () {
46979                         var endPoint = '/api/v1/commandList';
46980                         return this.resource(endPoint, {}).get();
46981                     };
46982                     APIEndPoint.prototype.execute = function (data) {
46983                         var endPoint = '/api/v1/execution';
46984                         var fd = new FormData();
46985                         fd.append('data', data);
46986                         return this.$http.post(endPoint, fd, {
46987                             headers: { 'Content-Type': undefined },
46988                             transformRequest: angular.identity
46989                         });
46990                     };
46991                     APIEndPoint.prototype.debug = function () {
46992                         var endPoint = '/api/v1/debug';
46993                         return this.$http.get(endPoint);
46994                     };
46995                     APIEndPoint.prototype.help = function (command) {
46996                         var endPoint = '/api/v1/help/' + command;
46997                         return this.$http.get(endPoint);
46998                     };
46999                     return APIEndPoint;
47000                 })();
47001                 services.APIEndPoint = APIEndPoint;
47002             })(services = app.services || (app.services = {}));
47003         })(app || (app = {}));
47004         var app;
47005         (function (app) {
47006             var services;
47007             (function (services) {
47008                 var MyModal = (function () {
47009                     function MyModal($uibModal) {
47010                         this.$uibModal = $uibModal;
47011                         this.modalOption = {
47012                             backdrop: true,
47013                             controller: null,
47014                             templateUrl: null,
47015                             size: null
47016                         };
47017                     }
47018                     MyModal.prototype.open = function (modalName) {
47019                         if (modalName === 'SelectCommand') {
47020                             this.modalOption.templateUrl = 'templates/select-command.html';
47021                             this.modalOption.size = 'lg';
47022                         }
47023                         return this.$uibModal.open(this.modalOption);
47024                     };
47025                     MyModal.prototype.selectCommand = function () {
47026                         this.modalOption.templateUrl = 'templates/select-command.html';
47027                         this.modalOption.controller = 'selectCommandController';
47028                         this.modalOption.controllerAs = 'c';
47029                         this.modalOption.size = 'lg';
47030                         return this.$uibModal.open(this.modalOption);
47031                     };
47032                     MyModal.prototype.preview = function () {
47033                         this.modalOption.templateUrl = 'templates/preview.html';
47034                         this.modalOption.controller = 'previewController';
47035                         this.modalOption.controllerAs = 'c';
47036                         this.modalOption.size = 'lg';
47037                         return this.$uibModal.open(this.modalOption);
47038                     };
47039                     MyModal.$inject = ['$uibModal'];
47040                     return MyModal;
47041                 })();
47042                 services.MyModal = MyModal;
47043             })(services = app.services || (app.services = {}));
47044         })(app || (app = {}));
47045         var app;
47046         (function (app) {
47047             var services;
47048             (function (services) {
47049                 var WebSocket = (function () {
47050                     function WebSocket($rootScope) {
47051                         this.$rootScope = $rootScope;
47052                         this.socket = io.connect();
47053                     }
47054                     WebSocket.prototype.on = function (eventName, callback) {
47055                         var socket = this.socket;
47056                         var rootScope = this.$rootScope;
47057                         socket.on(eventName, function () {
47058                             var args = arguments;
47059                             rootScope.$apply(function () {
47060                                 callback.apply(socket, args);
47061                             });
47062                         });
47063                     };
47064                     WebSocket.prototype.emit = function (eventName, data, callback) {
47065                         var socket = this.socket;
47066                         var rootScope = this.$rootScope;
47067                         this.socket.emit(eventName, data, function () {
47068                             var args = arguments;
47069                             rootScope.$apply(function () {
47070                                 if (callback)
47071                                     callback.apply(socket, args);
47072                             });
47073                         });
47074                     };
47075                     return WebSocket;
47076                 })();
47077                 services.WebSocket = WebSocket;
47078             })(services = app.services || (app.services = {}));
47079         })(app || (app = {}));
47080         var app;
47081         (function (app) {
47082             var directives;
47083             (function (directives) {
47084                 var Command = (function () {
47085                     function Command() {
47086                         this.restrict = 'E';
47087                         this.replace = true;
47088                         this.scope = true;
47089                         this.controller = 'commandController';
47090                         this.controllerAs = 'ctrl';
47091                         this.bindToController = {
47092                             index: '=',
47093                             name: '=',
47094                             remove: '&',
47095                             list: '='
47096                         };
47097                         this.templateUrl = 'templates/command.html';
47098                     }
47099                     Command.Factory = function () {
47100                         var directive = function () {
47101                             return new Command();
47102                         };
47103                         directive.$inject = [];
47104                         return directive;
47105                     };
47106                     return Command;
47107                 })();
47108                 directives.Command = Command;
47109                 var CommandController = (function () {
47110                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
47111                         this.APIEndPoint = APIEndPoint;
47112                         this.$scope = $scope;
47113                         this.MyModal = MyModal;
47114                         this.WebSocket = WebSocket;
47115                         this.$window = $window;
47116                         this.$rootScope = $rootScope;
47117                         var controller = this;
47118                         this.APIEndPoint
47119                             .getOptionControlFile(this.name)
47120                             .$promise
47121                             .then(function (result) {
47122                             controller.options = result.info;
47123                         });
47124                         this.APIEndPoint
47125                             .getDirectories()
47126                             .$promise
47127                             .then(function (result) {
47128                             controller.dirs = result.info;
47129                         });
47130                         this.heading = "[" + this.index + "]: dcdFilePrint";
47131                         this.isOpen = true;
47132                         this.$scope.$on('close', function () {
47133                             controller.isOpen = false;
47134                         });
47135                         function guid() {
47136                             function s4() {
47137                                 return Math.floor((1 + Math.random()) * 0x10000)
47138                                     .toString(16)
47139                                     .substring(1);
47140                             }
47141                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
47142                                 s4() + '-' + s4() + s4() + s4();
47143                         }
47144                         var uuid = guid();
47145                     }
47146                     CommandController.prototype.submit = function () {
47147                         var opt = [];
47148                         angular.forEach(this.options, function (option) {
47149                             var obj = {
47150                                 name: option.option,
47151                                 arguments: []
47152                             };
47153                             angular.forEach(option.arg, function (arg) {
47154                                 if (arg.input) {
47155                                     if (typeof arg.input === 'object') {
47156                                         obj.arguments.push(arg.input.name);
47157                                     }
47158                                     else {
47159                                         obj.arguments.push(arg.input);
47160                                     }
47161                                 }
47162                             });
47163                             if (obj.arguments.length > 0) {
47164                                 opt.push(obj);
47165                             }
47166                         });
47167                         var execObj = {
47168                             command: this.name,
47169                             workspace: this.workspace.fileId,
47170                             options: opt
47171                         };
47172                         this.APIEndPoint
47173                             .execute(JSON.stringify(execObj))
47174                             .then(function (result) {
47175                             console.log(result);
47176                         });
47177                     };
47178                     CommandController.prototype.removeMySelf = function (index) {
47179                         this.$scope.$destroy();
47180                         this.remove()(index, this.list);
47181                     };
47182                     CommandController.prototype.reloadFiles = function () {
47183                         var _this = this;
47184                         var fileId = this.workspace.fileId;
47185                         this.APIEndPoint
47186                             .getFiles(fileId)
47187                             .$promise
47188                             .then(function (result) {
47189                             var status = result.status;
47190                             if (status === 'success') {
47191                                 _this.files = result.info;
47192                             }
47193                             else {
47194                                 console.log(result.message);
47195                             }
47196                         });
47197                     };
47198                     CommandController.prototype.debug = function () {
47199                         console.log(this.$rootScope);
47200                         var div = angular.element(this.$window.document).find("div");
47201                         var consoleTag;
47202                         var parametersTag;
47203                         angular.forEach(div, function (v) {
47204                             if (v.className === "panel-body console") {
47205                                 consoleTag = v;
47206                             }
47207                             else if (v.className === "row parameters-console") {
47208                                 parametersTag = v;
47209                             }
47210                         });
47211                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
47212                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
47213                         consoleTag.style.height = consoleHeight;
47214                         consoleTag.style.width = consoleWidth;
47215                     };
47216                     CommandController.prototype.help = function () {
47217                         this.APIEndPoint
47218                             .help(this.name)
47219                             .then(function (result) {
47220                             console.log(result);
47221                         });
47222                     };
47223                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
47224                     return CommandController;
47225                 })();
47226                 directives.CommandController = CommandController;
47227             })(directives = app.directives || (app.directives = {}));
47228         })(app || (app = {}));
47229         var app;
47230         (function (app) {
47231             var directives;
47232             (function (directives) {
47233                 var HeaderMenu = (function () {
47234                     function HeaderMenu() {
47235                         this.restrict = 'E';
47236                         this.replace = true;
47237                         this.templateUrl = 'templates/header-menu.html';
47238                         this.controller = 'HeaderMenuController';
47239                         this.controllerAs = 'hmc';
47240                         this.scope = true;
47241                     }
47242                     HeaderMenu.Factory = function () {
47243                         var directive = function () {
47244                             return new HeaderMenu();
47245                         };
47246                         return directive;
47247                     };
47248                     return HeaderMenu;
47249                 })();
47250                 directives.HeaderMenu = HeaderMenu;
47251                 var HeaderMenuController = (function () {
47252                     function HeaderMenuController($state) {
47253                         this.$state = $state;
47254                         this.isExecution = this.$state.current.name === 'execution';
47255                         this.isWorkspace = this.$state.current.name === 'workspace';
47256                         this.isHistory = this.$state.current.name === 'history';
47257                     }
47258                     HeaderMenuController.prototype.transit = function (state) {
47259                         this.$state.go(state);
47260                     };
47261                     HeaderMenuController.$inject = ['$state'];
47262                     return HeaderMenuController;
47263                 })();
47264                 directives.HeaderMenuController = HeaderMenuController;
47265             })(directives = app.directives || (app.directives = {}));
47266         })(app || (app = {}));
47267         var app;
47268         (function (app) {
47269             var directives;
47270             (function (directives) {
47271                 var Option = (function () {
47272                     function Option() {
47273                         this.restrict = 'E';
47274                         this.replace = true;
47275                         this.controller = 'optionController';
47276                         this.bindToController = {
47277                             info: '=',
47278                             files: '='
47279                         };
47280                         this.scope = true;
47281                         this.templateUrl = 'templates/option.html';
47282                         this.controllerAs = 'ctrl';
47283                     }
47284                     Option.Factory = function () {
47285                         var directive = function () {
47286                             return new Option();
47287                         };
47288                         directive.$inject = [];
47289                         return directive;
47290                     };
47291                     return Option;
47292                 })();
47293                 directives.Option = Option;
47294                 var OptionController = (function () {
47295                     function OptionController() {
47296                         var controller = this;
47297                         angular.forEach(controller.info.arg, function (arg) {
47298                             if (arg.initialValue) {
47299                                 if (arg.formType === 'number') {
47300                                     arg.input = parseInt(arg.initialValue);
47301                                 }
47302                                 else {
47303                                     arg.input = arg.initialValue;
47304                                 }
47305                             }
47306                         });
47307                     }
47308                     OptionController.$inject = [];
47309                     return OptionController;
47310                 })();
47311                 directives.OptionController = OptionController;
47312             })(directives = app.directives || (app.directives = {}));
47313         })(app || (app = {}));
47314         var app;
47315         (function (app) {
47316             var directives;
47317             (function (directives) {
47318                 var Directory = (function () {
47319                     function Directory() {
47320                         this.restrict = 'E';
47321                         this.replace = true;
47322                         this.controller = 'directoryController';
47323                         this.controllerAs = 'ctrl';
47324                         this.bindToController = {
47325                             info: '=',
47326                             add: '&',
47327                             list: '=',
47328                             files: '='
47329                         };
47330                         this.templateUrl = 'templates/directory.html';
47331                     }
47332                     Directory.Factory = function () {
47333                         var directive = function () {
47334                             return new Directory();
47335                         };
47336                         return directive;
47337                     };
47338                     return Directory;
47339                 })();
47340                 directives.Directory = Directory;
47341                 var DirectoryController = (function () {
47342                     function DirectoryController(APIEndPoint, $scope) {
47343                         this.APIEndPoint = APIEndPoint;
47344                         this.$scope = $scope;
47345                         var controller = this;
47346                         this.APIEndPoint
47347                             .getFiles(this.info.fileId)
47348                             .$promise
47349                             .then(function (result) {
47350                             if (result.status === 'success') {
47351                                 controller.files = result.info;
47352                                 angular.forEach(result.info, function (file) {
47353                                     if (file.fileType === '0') {
47354                                         var o = file;
47355                                         if (controller.info.path === '/') {
47356                                             o.path = '/' + file.name;
47357                                         }
47358                                         else {
47359                                             o.path = controller.info.path + '/' + file.name;
47360                                         }
47361                                         controller.add()(o, controller.list);
47362                                     }
47363                                 });
47364                             }
47365                             ;
47366                         });
47367                     }
47368                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
47369                     return DirectoryController;
47370                 })();
47371                 directives.DirectoryController = DirectoryController;
47372             })(directives = app.directives || (app.directives = {}));
47373         })(app || (app = {}));
47374         var app;
47375         (function (app) {
47376             var controllers;
47377             (function (controllers) {
47378                 var Execution = (function () {
47379                     function Execution(MyModal, $scope) {
47380                         this.MyModal = MyModal;
47381                         this.$scope = $scope;
47382                         this.commandInfoList = [];
47383                     }
47384                     ;
47385                     Execution.prototype.add = function () {
47386                         this.$scope.$broadcast('close');
47387                         var commandInfoList = this.commandInfoList;
47388                         var commandInstance = this.MyModal.selectCommand();
47389                         commandInstance
47390                             .result
47391                             .then(function (command) {
47392                             commandInfoList.push(new app.declares.CommandInfo(command));
47393                         });
47394                     };
47395                     Execution.prototype.open = function () {
47396                         var result = this.MyModal.open('SelectCommand');
47397                         console.log(result);
47398                     };
47399                     Execution.prototype.remove = function (index, list) {
47400                         list.splice(index, 1);
47401                     };
47402                     Execution.prototype.close = function () {
47403                         console.log("close");
47404                     };
47405                     Execution.$inject = ['MyModal', '$scope'];
47406                     return Execution;
47407                 })();
47408                 controllers.Execution = Execution;
47409             })(controllers = app.controllers || (app.controllers = {}));
47410         })(app || (app = {}));
47411         var app;
47412         (function (app) {
47413             var controllers;
47414             (function (controllers) {
47415                 var Workspace = (function () {
47416                     function Workspace($scope, APIEndPoint, MyModal) {
47417                         this.$scope = $scope;
47418                         this.APIEndPoint = APIEndPoint;
47419                         this.MyModal = MyModal;
47420                         this.directoryList = [];
47421                         var controller = this;
47422                         var directoryList = this.directoryList;
47423                         var o = {
47424                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
47425                             name: '',
47426                             parentId: '',
47427                             fileType: '',
47428                             createdAt: '',
47429                             updatedAt: '',
47430                             path: '/'
47431                         };
47432                         directoryList.push(o);
47433                     }
47434                     Workspace.prototype.addDirectory = function (info, directoryList) {
47435                         directoryList.push(info);
47436                     };
47437                     Workspace.prototype.debug = function () {
47438                         this.MyModal.preview();
47439                     };
47440                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
47441                     return Workspace;
47442                 })();
47443                 controllers.Workspace = Workspace;
47444             })(controllers = app.controllers || (app.controllers = {}));
47445         })(app || (app = {}));
47446         var app;
47447         (function (app) {
47448             var controllers;
47449             (function (controllers) {
47450                 var History = (function () {
47451                     function History($scope) {
47452                         this.page = "History";
47453                     }
47454                     History.$inject = ['$scope'];
47455                     return History;
47456                 })();
47457                 controllers.History = History;
47458             })(controllers = app.controllers || (app.controllers = {}));
47459         })(app || (app = {}));
47460         var app;
47461         (function (app) {
47462             var controllers;
47463             (function (controllers) {
47464                 var SelectCommand = (function () {
47465                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
47466                         this.APIEndPoint = APIEndPoint;
47467                         this.$modalInstance = $modalInstance;
47468                         var controller = this;
47469                         this.APIEndPoint
47470                             .getTags()
47471                             .$promise.then(function (result) {
47472                             controller.tags = result.info;
47473                         });
47474                         this.APIEndPoint
47475                             .getCommands()
47476                             .$promise.then(function (result) {
47477                             controller.commands = result.info;
47478                         });
47479                         this.currentTag = 'all';
47480                     }
47481                     SelectCommand.prototype.changeTag = function (tag) {
47482                         this.currentTag = tag;
47483                     };
47484                     SelectCommand.prototype.selectCommand = function (command) {
47485                         this.$modalInstance.close(command);
47486                     };
47487                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47488                     return SelectCommand;
47489                 })();
47490                 controllers.SelectCommand = SelectCommand;
47491             })(controllers = app.controllers || (app.controllers = {}));
47492         })(app || (app = {}));
47493         var app;
47494         (function (app) {
47495             var controllers;
47496             (function (controllers) {
47497                 var Preview = (function () {
47498                     function Preview($scope, APIEndPoint, $modalInstance) {
47499                         this.APIEndPoint = APIEndPoint;
47500                         this.$modalInstance = $modalInstance;
47501                         var controller = this;
47502                         console.log('preview');
47503                     }
47504                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47505                     return Preview;
47506                 })();
47507                 controllers.Preview = Preview;
47508             })(controllers = app.controllers || (app.controllers = {}));
47509         })(app || (app = {}));
47510         var filters;
47511         (function (filters) {
47512             function Tag() {
47513                 return function (commands, tag) {
47514                     var result = [];
47515                     angular.forEach(commands, function (command) {
47516                         var flag = false;
47517                         angular.forEach(command.tags, function (value) {
47518                             if (tag === value)
47519                                 flag = true;
47520                         });
47521                         if (flag)
47522                             result.push(command);
47523                     });
47524                     return result;
47525                 };
47526             }
47527             filters.Tag = Tag;
47528         })(filters || (filters = {}));
47529         var app;
47530         (function (app) {
47531             'use strict';
47532             var appName = 'zephyr';
47533             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
47534             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
47535                 $urlRouterProvider.otherwise('/execution');
47536                 $locationProvider.html5Mode({
47537                     enabled: true,
47538                     requireBase: false
47539                 });
47540                 $stateProvider
47541                     .state('execution', {
47542                     url: '/execution',
47543                     templateUrl: 'templates/execution.html',
47544                     controller: 'executionController',
47545                     controllerAs: 'c'
47546                 })
47547                     .state('workspace', {
47548                     url: '/workspace',
47549                     templateUrl: 'templates/workspace.html',
47550                     controller: 'workspaceController',
47551                     controllerAs: 'c'
47552                 })
47553                     .state('history', {
47554                     url: '/history',
47555                     templateUrl: 'templates/history.html',
47556                     controller: 'historyController',
47557                     controllerAs: 'c'
47558                 });
47559             });
47560             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
47561             app.zephyr.service('MyModal', app.services.MyModal);
47562             app.zephyr.service('WebSocket', app.services.WebSocket);
47563             app.zephyr.filter('Tag', filters.Tag);
47564             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
47565             app.zephyr.controller('previewController', app.controllers.Preview);
47566             app.zephyr.controller('executionController', app.controllers.Execution);
47567             app.zephyr.controller('workspaceController', app.controllers.Workspace);
47568             app.zephyr.controller('historyController', app.controllers.History);
47569             app.zephyr.controller('commandController', app.directives.CommandController);
47570             app.zephyr.controller('optionController', app.directives.OptionController);
47571             app.zephyr.controller('directoryController', app.directives.DirectoryController);
47572             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
47573             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
47574             app.zephyr.directive('command', app.directives.Command.Factory());
47575             app.zephyr.directive('option', app.directives.Option.Factory());
47576             app.zephyr.directive('directory', app.directives.Directory.Factory());
47577         })(app || (app = {}));
47578
47579
47580 /***/ },
47581 /* 18 */
47582 /***/ function(module, exports) {
47583
47584         var app;
47585         (function (app) {
47586             var declares;
47587             (function (declares) {
47588                 var CommandInfo = (function () {
47589                     function CommandInfo(name) {
47590                         this.name = name;
47591                     }
47592                     return CommandInfo;
47593                 })();
47594                 declares.CommandInfo = CommandInfo;
47595             })(declares = app.declares || (app.declares = {}));
47596         })(app || (app = {}));
47597         var app;
47598         (function (app) {
47599             var services;
47600             (function (services) {
47601                 var APIEndPoint = (function () {
47602                     function APIEndPoint($resource, $http) {
47603                         this.$resource = $resource;
47604                         this.$http = $http;
47605                     }
47606                     APIEndPoint.prototype.resource = function (endPoint, data) {
47607                         var customAction = {
47608                             method: 'GET',
47609                             isArray: false
47610                         };
47611                         var execute = {
47612                             method: 'POST',
47613                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
47614                         };
47615                         return this.$resource(endPoint, {}, { execute: execute });
47616                     };
47617                     APIEndPoint.prototype.getOptionControlFile = function (command) {
47618                         var endPoint = '/api/v1/optionControlFile/' + command;
47619                         return this.resource(endPoint, {}).get();
47620                     };
47621                     APIEndPoint.prototype.getFiles = function (fileId) {
47622                         var endPoint = '/api/v1/workspace';
47623                         if (fileId) {
47624                             endPoint += '/' + fileId;
47625                         }
47626                         return this.resource(endPoint, {}).get();
47627                     };
47628                     APIEndPoint.prototype.getDirectories = function () {
47629                         var endPoint = '/api/v1/all/workspace/directory';
47630                         return this.resource(endPoint, {}).get();
47631                     };
47632                     APIEndPoint.prototype.getTags = function () {
47633                         var endPoint = '/api/v1/tagList';
47634                         return this.resource(endPoint, {}).get();
47635                     };
47636                     APIEndPoint.prototype.getCommands = function () {
47637                         var endPoint = '/api/v1/commandList';
47638                         return this.resource(endPoint, {}).get();
47639                     };
47640                     APIEndPoint.prototype.execute = function (data) {
47641                         var endPoint = '/api/v1/execution';
47642                         var fd = new FormData();
47643                         fd.append('data', data);
47644                         return this.$http.post(endPoint, fd, {
47645                             headers: { 'Content-Type': undefined },
47646                             transformRequest: angular.identity
47647                         });
47648                     };
47649                     APIEndPoint.prototype.debug = function () {
47650                         var endPoint = '/api/v1/debug';
47651                         return this.$http.get(endPoint);
47652                     };
47653                     APIEndPoint.prototype.help = function (command) {
47654                         var endPoint = '/api/v1/help/' + command;
47655                         return this.$http.get(endPoint);
47656                     };
47657                     return APIEndPoint;
47658                 })();
47659                 services.APIEndPoint = APIEndPoint;
47660             })(services = app.services || (app.services = {}));
47661         })(app || (app = {}));
47662         var app;
47663         (function (app) {
47664             var services;
47665             (function (services) {
47666                 var MyModal = (function () {
47667                     function MyModal($uibModal) {
47668                         this.$uibModal = $uibModal;
47669                         this.modalOption = {
47670                             backdrop: true,
47671                             controller: null,
47672                             templateUrl: null,
47673                             size: null
47674                         };
47675                     }
47676                     MyModal.prototype.open = function (modalName) {
47677                         if (modalName === 'SelectCommand') {
47678                             this.modalOption.templateUrl = 'templates/select-command.html';
47679                             this.modalOption.size = 'lg';
47680                         }
47681                         return this.$uibModal.open(this.modalOption);
47682                     };
47683                     MyModal.prototype.selectCommand = function () {
47684                         this.modalOption.templateUrl = 'templates/select-command.html';
47685                         this.modalOption.controller = 'selectCommandController';
47686                         this.modalOption.controllerAs = 'c';
47687                         this.modalOption.size = 'lg';
47688                         return this.$uibModal.open(this.modalOption);
47689                     };
47690                     MyModal.prototype.preview = function () {
47691                         this.modalOption.templateUrl = 'templates/preview.html';
47692                         this.modalOption.controller = 'previewController';
47693                         this.modalOption.controllerAs = 'c';
47694                         this.modalOption.size = 'lg';
47695                         return this.$uibModal.open(this.modalOption);
47696                     };
47697                     MyModal.$inject = ['$uibModal'];
47698                     return MyModal;
47699                 })();
47700                 services.MyModal = MyModal;
47701             })(services = app.services || (app.services = {}));
47702         })(app || (app = {}));
47703         var app;
47704         (function (app) {
47705             var services;
47706             (function (services) {
47707                 var WebSocket = (function () {
47708                     function WebSocket($rootScope) {
47709                         this.$rootScope = $rootScope;
47710                         this.socket = io.connect();
47711                     }
47712                     WebSocket.prototype.on = function (eventName, callback) {
47713                         var socket = this.socket;
47714                         var rootScope = this.$rootScope;
47715                         socket.on(eventName, function () {
47716                             var args = arguments;
47717                             rootScope.$apply(function () {
47718                                 callback.apply(socket, args);
47719                             });
47720                         });
47721                     };
47722                     WebSocket.prototype.emit = function (eventName, data, callback) {
47723                         var socket = this.socket;
47724                         var rootScope = this.$rootScope;
47725                         this.socket.emit(eventName, data, function () {
47726                             var args = arguments;
47727                             rootScope.$apply(function () {
47728                                 if (callback)
47729                                     callback.apply(socket, args);
47730                             });
47731                         });
47732                     };
47733                     return WebSocket;
47734                 })();
47735                 services.WebSocket = WebSocket;
47736             })(services = app.services || (app.services = {}));
47737         })(app || (app = {}));
47738         var app;
47739         (function (app) {
47740             var directives;
47741             (function (directives) {
47742                 var Command = (function () {
47743                     function Command() {
47744                         this.restrict = 'E';
47745                         this.replace = true;
47746                         this.scope = true;
47747                         this.controller = 'commandController';
47748                         this.controllerAs = 'ctrl';
47749                         this.bindToController = {
47750                             index: '=',
47751                             name: '=',
47752                             remove: '&',
47753                             list: '='
47754                         };
47755                         this.templateUrl = 'templates/command.html';
47756                     }
47757                     Command.Factory = function () {
47758                         var directive = function () {
47759                             return new Command();
47760                         };
47761                         directive.$inject = [];
47762                         return directive;
47763                     };
47764                     return Command;
47765                 })();
47766                 directives.Command = Command;
47767                 var CommandController = (function () {
47768                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
47769                         this.APIEndPoint = APIEndPoint;
47770                         this.$scope = $scope;
47771                         this.MyModal = MyModal;
47772                         this.WebSocket = WebSocket;
47773                         this.$window = $window;
47774                         this.$rootScope = $rootScope;
47775                         var controller = this;
47776                         this.APIEndPoint
47777                             .getOptionControlFile(this.name)
47778                             .$promise
47779                             .then(function (result) {
47780                             controller.options = result.info;
47781                         });
47782                         this.APIEndPoint
47783                             .getDirectories()
47784                             .$promise
47785                             .then(function (result) {
47786                             controller.dirs = result.info;
47787                         });
47788                         this.heading = "[" + this.index + "]: dcdFilePrint";
47789                         this.isOpen = true;
47790                         this.$scope.$on('close', function () {
47791                             controller.isOpen = false;
47792                         });
47793                         function guid() {
47794                             function s4() {
47795                                 return Math.floor((1 + Math.random()) * 0x10000)
47796                                     .toString(16)
47797                                     .substring(1);
47798                             }
47799                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
47800                                 s4() + '-' + s4() + s4() + s4();
47801                         }
47802                         var uuid = guid();
47803                     }
47804                     CommandController.prototype.submit = function () {
47805                         var opt = [];
47806                         angular.forEach(this.options, function (option) {
47807                             var obj = {
47808                                 name: option.option,
47809                                 arguments: []
47810                             };
47811                             angular.forEach(option.arg, function (arg) {
47812                                 if (arg.input) {
47813                                     if (typeof arg.input === 'object') {
47814                                         obj.arguments.push(arg.input.name);
47815                                     }
47816                                     else {
47817                                         obj.arguments.push(arg.input);
47818                                     }
47819                                 }
47820                             });
47821                             if (obj.arguments.length > 0) {
47822                                 opt.push(obj);
47823                             }
47824                         });
47825                         var execObj = {
47826                             command: this.name,
47827                             workspace: this.workspace.fileId,
47828                             options: opt
47829                         };
47830                         this.APIEndPoint
47831                             .execute(JSON.stringify(execObj))
47832                             .then(function (result) {
47833                             console.log(result);
47834                         });
47835                     };
47836                     CommandController.prototype.removeMySelf = function (index) {
47837                         this.$scope.$destroy();
47838                         this.remove()(index, this.list);
47839                     };
47840                     CommandController.prototype.reloadFiles = function () {
47841                         var _this = this;
47842                         var fileId = this.workspace.fileId;
47843                         this.APIEndPoint
47844                             .getFiles(fileId)
47845                             .$promise
47846                             .then(function (result) {
47847                             var status = result.status;
47848                             if (status === 'success') {
47849                                 _this.files = result.info;
47850                             }
47851                             else {
47852                                 console.log(result.message);
47853                             }
47854                         });
47855                     };
47856                     CommandController.prototype.debug = function () {
47857                         console.log(this.$rootScope);
47858                         var div = angular.element(this.$window.document).find("div");
47859                         var consoleTag;
47860                         var parametersTag;
47861                         angular.forEach(div, function (v) {
47862                             if (v.className === "panel-body console") {
47863                                 consoleTag = v;
47864                             }
47865                             else if (v.className === "row parameters-console") {
47866                                 parametersTag = v;
47867                             }
47868                         });
47869                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
47870                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
47871                         consoleTag.style.height = consoleHeight;
47872                         consoleTag.style.width = consoleWidth;
47873                     };
47874                     CommandController.prototype.help = function () {
47875                         this.APIEndPoint
47876                             .help(this.name)
47877                             .then(function (result) {
47878                             console.log(result);
47879                         });
47880                     };
47881                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
47882                     return CommandController;
47883                 })();
47884                 directives.CommandController = CommandController;
47885             })(directives = app.directives || (app.directives = {}));
47886         })(app || (app = {}));
47887         var app;
47888         (function (app) {
47889             var directives;
47890             (function (directives) {
47891                 var HeaderMenu = (function () {
47892                     function HeaderMenu() {
47893                         this.restrict = 'E';
47894                         this.replace = true;
47895                         this.templateUrl = 'templates/header-menu.html';
47896                         this.controller = 'HeaderMenuController';
47897                         this.controllerAs = 'hmc';
47898                         this.scope = true;
47899                     }
47900                     HeaderMenu.Factory = function () {
47901                         var directive = function () {
47902                             return new HeaderMenu();
47903                         };
47904                         return directive;
47905                     };
47906                     return HeaderMenu;
47907                 })();
47908                 directives.HeaderMenu = HeaderMenu;
47909                 var HeaderMenuController = (function () {
47910                     function HeaderMenuController($state) {
47911                         this.$state = $state;
47912                         this.isExecution = this.$state.current.name === 'execution';
47913                         this.isWorkspace = this.$state.current.name === 'workspace';
47914                         this.isHistory = this.$state.current.name === 'history';
47915                     }
47916                     HeaderMenuController.prototype.transit = function (state) {
47917                         this.$state.go(state);
47918                     };
47919                     HeaderMenuController.$inject = ['$state'];
47920                     return HeaderMenuController;
47921                 })();
47922                 directives.HeaderMenuController = HeaderMenuController;
47923             })(directives = app.directives || (app.directives = {}));
47924         })(app || (app = {}));
47925         var app;
47926         (function (app) {
47927             var directives;
47928             (function (directives) {
47929                 var Option = (function () {
47930                     function Option() {
47931                         this.restrict = 'E';
47932                         this.replace = true;
47933                         this.controller = 'optionController';
47934                         this.bindToController = {
47935                             info: '=',
47936                             files: '='
47937                         };
47938                         this.scope = true;
47939                         this.templateUrl = 'templates/option.html';
47940                         this.controllerAs = 'ctrl';
47941                     }
47942                     Option.Factory = function () {
47943                         var directive = function () {
47944                             return new Option();
47945                         };
47946                         directive.$inject = [];
47947                         return directive;
47948                     };
47949                     return Option;
47950                 })();
47951                 directives.Option = Option;
47952                 var OptionController = (function () {
47953                     function OptionController() {
47954                         var controller = this;
47955                         angular.forEach(controller.info.arg, function (arg) {
47956                             if (arg.initialValue) {
47957                                 if (arg.formType === 'number') {
47958                                     arg.input = parseInt(arg.initialValue);
47959                                 }
47960                                 else {
47961                                     arg.input = arg.initialValue;
47962                                 }
47963                             }
47964                         });
47965                     }
47966                     OptionController.$inject = [];
47967                     return OptionController;
47968                 })();
47969                 directives.OptionController = OptionController;
47970             })(directives = app.directives || (app.directives = {}));
47971         })(app || (app = {}));
47972         var app;
47973         (function (app) {
47974             var directives;
47975             (function (directives) {
47976                 var Directory = (function () {
47977                     function Directory() {
47978                         this.restrict = 'E';
47979                         this.replace = true;
47980                         this.controller = 'directoryController';
47981                         this.controllerAs = 'ctrl';
47982                         this.bindToController = {
47983                             info: '=',
47984                             add: '&',
47985                             list: '=',
47986                             files: '='
47987                         };
47988                         this.templateUrl = 'templates/directory.html';
47989                     }
47990                     Directory.Factory = function () {
47991                         var directive = function () {
47992                             return new Directory();
47993                         };
47994                         return directive;
47995                     };
47996                     return Directory;
47997                 })();
47998                 directives.Directory = Directory;
47999                 var DirectoryController = (function () {
48000                     function DirectoryController(APIEndPoint, $scope) {
48001                         this.APIEndPoint = APIEndPoint;
48002                         this.$scope = $scope;
48003                         var controller = this;
48004                         this.APIEndPoint
48005                             .getFiles(this.info.fileId)
48006                             .$promise
48007                             .then(function (result) {
48008                             if (result.status === 'success') {
48009                                 controller.files = result.info;
48010                                 angular.forEach(result.info, function (file) {
48011                                     if (file.fileType === '0') {
48012                                         var o = file;
48013                                         if (controller.info.path === '/') {
48014                                             o.path = '/' + file.name;
48015                                         }
48016                                         else {
48017                                             o.path = controller.info.path + '/' + file.name;
48018                                         }
48019                                         controller.add()(o, controller.list);
48020                                     }
48021                                 });
48022                             }
48023                             ;
48024                         });
48025                     }
48026                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
48027                     return DirectoryController;
48028                 })();
48029                 directives.DirectoryController = DirectoryController;
48030             })(directives = app.directives || (app.directives = {}));
48031         })(app || (app = {}));
48032         var app;
48033         (function (app) {
48034             var controllers;
48035             (function (controllers) {
48036                 var Execution = (function () {
48037                     function Execution(MyModal, $scope) {
48038                         this.MyModal = MyModal;
48039                         this.$scope = $scope;
48040                         this.commandInfoList = [];
48041                     }
48042                     ;
48043                     Execution.prototype.add = function () {
48044                         this.$scope.$broadcast('close');
48045                         var commandInfoList = this.commandInfoList;
48046                         var commandInstance = this.MyModal.selectCommand();
48047                         commandInstance
48048                             .result
48049                             .then(function (command) {
48050                             commandInfoList.push(new app.declares.CommandInfo(command));
48051                         });
48052                     };
48053                     Execution.prototype.open = function () {
48054                         var result = this.MyModal.open('SelectCommand');
48055                         console.log(result);
48056                     };
48057                     Execution.prototype.remove = function (index, list) {
48058                         list.splice(index, 1);
48059                     };
48060                     Execution.prototype.close = function () {
48061                         console.log("close");
48062                     };
48063                     Execution.$inject = ['MyModal', '$scope'];
48064                     return Execution;
48065                 })();
48066                 controllers.Execution = Execution;
48067             })(controllers = app.controllers || (app.controllers = {}));
48068         })(app || (app = {}));
48069         var app;
48070         (function (app) {
48071             var controllers;
48072             (function (controllers) {
48073                 var Workspace = (function () {
48074                     function Workspace($scope, APIEndPoint, MyModal) {
48075                         this.$scope = $scope;
48076                         this.APIEndPoint = APIEndPoint;
48077                         this.MyModal = MyModal;
48078                         this.directoryList = [];
48079                         var controller = this;
48080                         var directoryList = this.directoryList;
48081                         var o = {
48082                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
48083                             name: '',
48084                             parentId: '',
48085                             fileType: '',
48086                             createdAt: '',
48087                             updatedAt: '',
48088                             path: '/'
48089                         };
48090                         directoryList.push(o);
48091                     }
48092                     Workspace.prototype.addDirectory = function (info, directoryList) {
48093                         directoryList.push(info);
48094                     };
48095                     Workspace.prototype.debug = function () {
48096                         this.MyModal.preview();
48097                     };
48098                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
48099                     return Workspace;
48100                 })();
48101                 controllers.Workspace = Workspace;
48102             })(controllers = app.controllers || (app.controllers = {}));
48103         })(app || (app = {}));
48104         var app;
48105         (function (app) {
48106             var controllers;
48107             (function (controllers) {
48108                 var History = (function () {
48109                     function History($scope) {
48110                         this.page = "History";
48111                     }
48112                     History.$inject = ['$scope'];
48113                     return History;
48114                 })();
48115                 controllers.History = History;
48116             })(controllers = app.controllers || (app.controllers = {}));
48117         })(app || (app = {}));
48118         var app;
48119         (function (app) {
48120             var controllers;
48121             (function (controllers) {
48122                 var SelectCommand = (function () {
48123                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
48124                         this.APIEndPoint = APIEndPoint;
48125                         this.$modalInstance = $modalInstance;
48126                         var controller = this;
48127                         this.APIEndPoint
48128                             .getTags()
48129                             .$promise.then(function (result) {
48130                             controller.tags = result.info;
48131                         });
48132                         this.APIEndPoint
48133                             .getCommands()
48134                             .$promise.then(function (result) {
48135                             controller.commands = result.info;
48136                         });
48137                         this.currentTag = 'all';
48138                     }
48139                     SelectCommand.prototype.changeTag = function (tag) {
48140                         this.currentTag = tag;
48141                     };
48142                     SelectCommand.prototype.selectCommand = function (command) {
48143                         this.$modalInstance.close(command);
48144                     };
48145                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48146                     return SelectCommand;
48147                 })();
48148                 controllers.SelectCommand = SelectCommand;
48149             })(controllers = app.controllers || (app.controllers = {}));
48150         })(app || (app = {}));
48151         var app;
48152         (function (app) {
48153             var controllers;
48154             (function (controllers) {
48155                 var Preview = (function () {
48156                     function Preview($scope, APIEndPoint, $modalInstance) {
48157                         this.APIEndPoint = APIEndPoint;
48158                         this.$modalInstance = $modalInstance;
48159                         var controller = this;
48160                         console.log('preview');
48161                     }
48162                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48163                     return Preview;
48164                 })();
48165                 controllers.Preview = Preview;
48166             })(controllers = app.controllers || (app.controllers = {}));
48167         })(app || (app = {}));
48168         var filters;
48169         (function (filters) {
48170             function Tag() {
48171                 return function (commands, tag) {
48172                     var result = [];
48173                     angular.forEach(commands, function (command) {
48174                         var flag = false;
48175                         angular.forEach(command.tags, function (value) {
48176                             if (tag === value)
48177                                 flag = true;
48178                         });
48179                         if (flag)
48180                             result.push(command);
48181                     });
48182                     return result;
48183                 };
48184             }
48185             filters.Tag = Tag;
48186         })(filters || (filters = {}));
48187         var app;
48188         (function (app) {
48189             'use strict';
48190             var appName = 'zephyr';
48191             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
48192             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
48193                 $urlRouterProvider.otherwise('/execution');
48194                 $locationProvider.html5Mode({
48195                     enabled: true,
48196                     requireBase: false
48197                 });
48198                 $stateProvider
48199                     .state('execution', {
48200                     url: '/execution',
48201                     templateUrl: 'templates/execution.html',
48202                     controller: 'executionController',
48203                     controllerAs: 'c'
48204                 })
48205                     .state('workspace', {
48206                     url: '/workspace',
48207                     templateUrl: 'templates/workspace.html',
48208                     controller: 'workspaceController',
48209                     controllerAs: 'c'
48210                 })
48211                     .state('history', {
48212                     url: '/history',
48213                     templateUrl: 'templates/history.html',
48214                     controller: 'historyController',
48215                     controllerAs: 'c'
48216                 });
48217             });
48218             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
48219             app.zephyr.service('MyModal', app.services.MyModal);
48220             app.zephyr.service('WebSocket', app.services.WebSocket);
48221             app.zephyr.filter('Tag', filters.Tag);
48222             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
48223             app.zephyr.controller('previewController', app.controllers.Preview);
48224             app.zephyr.controller('executionController', app.controllers.Execution);
48225             app.zephyr.controller('workspaceController', app.controllers.Workspace);
48226             app.zephyr.controller('historyController', app.controllers.History);
48227             app.zephyr.controller('commandController', app.directives.CommandController);
48228             app.zephyr.controller('optionController', app.directives.OptionController);
48229             app.zephyr.controller('directoryController', app.directives.DirectoryController);
48230             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
48231             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
48232             app.zephyr.directive('command', app.directives.Command.Factory());
48233             app.zephyr.directive('option', app.directives.Option.Factory());
48234             app.zephyr.directive('directory', app.directives.Directory.Factory());
48235         })(app || (app = {}));
48236
48237
48238 /***/ },
48239 /* 19 */
48240 /***/ function(module, exports) {
48241
48242         var app;
48243         (function (app) {
48244             var declares;
48245             (function (declares) {
48246                 var CommandInfo = (function () {
48247                     function CommandInfo(name) {
48248                         this.name = name;
48249                     }
48250                     return CommandInfo;
48251                 })();
48252                 declares.CommandInfo = CommandInfo;
48253             })(declares = app.declares || (app.declares = {}));
48254         })(app || (app = {}));
48255         var app;
48256         (function (app) {
48257             var services;
48258             (function (services) {
48259                 var APIEndPoint = (function () {
48260                     function APIEndPoint($resource, $http) {
48261                         this.$resource = $resource;
48262                         this.$http = $http;
48263                     }
48264                     APIEndPoint.prototype.resource = function (endPoint, data) {
48265                         var customAction = {
48266                             method: 'GET',
48267                             isArray: false
48268                         };
48269                         var execute = {
48270                             method: 'POST',
48271                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
48272                         };
48273                         return this.$resource(endPoint, {}, { execute: execute });
48274                     };
48275                     APIEndPoint.prototype.getOptionControlFile = function (command) {
48276                         var endPoint = '/api/v1/optionControlFile/' + command;
48277                         return this.resource(endPoint, {}).get();
48278                     };
48279                     APIEndPoint.prototype.getFiles = function (fileId) {
48280                         var endPoint = '/api/v1/workspace';
48281                         if (fileId) {
48282                             endPoint += '/' + fileId;
48283                         }
48284                         return this.resource(endPoint, {}).get();
48285                     };
48286                     APIEndPoint.prototype.getDirectories = function () {
48287                         var endPoint = '/api/v1/all/workspace/directory';
48288                         return this.resource(endPoint, {}).get();
48289                     };
48290                     APIEndPoint.prototype.getTags = function () {
48291                         var endPoint = '/api/v1/tagList';
48292                         return this.resource(endPoint, {}).get();
48293                     };
48294                     APIEndPoint.prototype.getCommands = function () {
48295                         var endPoint = '/api/v1/commandList';
48296                         return this.resource(endPoint, {}).get();
48297                     };
48298                     APIEndPoint.prototype.execute = function (data) {
48299                         var endPoint = '/api/v1/execution';
48300                         var fd = new FormData();
48301                         fd.append('data', data);
48302                         return this.$http.post(endPoint, fd, {
48303                             headers: { 'Content-Type': undefined },
48304                             transformRequest: angular.identity
48305                         });
48306                     };
48307                     APIEndPoint.prototype.debug = function () {
48308                         var endPoint = '/api/v1/debug';
48309                         return this.$http.get(endPoint);
48310                     };
48311                     APIEndPoint.prototype.help = function (command) {
48312                         var endPoint = '/api/v1/help/' + command;
48313                         return this.$http.get(endPoint);
48314                     };
48315                     return APIEndPoint;
48316                 })();
48317                 services.APIEndPoint = APIEndPoint;
48318             })(services = app.services || (app.services = {}));
48319         })(app || (app = {}));
48320         var app;
48321         (function (app) {
48322             var services;
48323             (function (services) {
48324                 var MyModal = (function () {
48325                     function MyModal($uibModal) {
48326                         this.$uibModal = $uibModal;
48327                         this.modalOption = {
48328                             backdrop: true,
48329                             controller: null,
48330                             templateUrl: null,
48331                             size: null
48332                         };
48333                     }
48334                     MyModal.prototype.open = function (modalName) {
48335                         if (modalName === 'SelectCommand') {
48336                             this.modalOption.templateUrl = 'templates/select-command.html';
48337                             this.modalOption.size = 'lg';
48338                         }
48339                         return this.$uibModal.open(this.modalOption);
48340                     };
48341                     MyModal.prototype.selectCommand = function () {
48342                         this.modalOption.templateUrl = 'templates/select-command.html';
48343                         this.modalOption.controller = 'selectCommandController';
48344                         this.modalOption.controllerAs = 'c';
48345                         this.modalOption.size = 'lg';
48346                         return this.$uibModal.open(this.modalOption);
48347                     };
48348                     MyModal.prototype.preview = function () {
48349                         this.modalOption.templateUrl = 'templates/preview.html';
48350                         this.modalOption.controller = 'previewController';
48351                         this.modalOption.controllerAs = 'c';
48352                         this.modalOption.size = 'lg';
48353                         return this.$uibModal.open(this.modalOption);
48354                     };
48355                     MyModal.$inject = ['$uibModal'];
48356                     return MyModal;
48357                 })();
48358                 services.MyModal = MyModal;
48359             })(services = app.services || (app.services = {}));
48360         })(app || (app = {}));
48361         var app;
48362         (function (app) {
48363             var services;
48364             (function (services) {
48365                 var WebSocket = (function () {
48366                     function WebSocket($rootScope) {
48367                         this.$rootScope = $rootScope;
48368                         this.socket = io.connect();
48369                     }
48370                     WebSocket.prototype.on = function (eventName, callback) {
48371                         var socket = this.socket;
48372                         var rootScope = this.$rootScope;
48373                         socket.on(eventName, function () {
48374                             var args = arguments;
48375                             rootScope.$apply(function () {
48376                                 callback.apply(socket, args);
48377                             });
48378                         });
48379                     };
48380                     WebSocket.prototype.emit = function (eventName, data, callback) {
48381                         var socket = this.socket;
48382                         var rootScope = this.$rootScope;
48383                         this.socket.emit(eventName, data, function () {
48384                             var args = arguments;
48385                             rootScope.$apply(function () {
48386                                 if (callback)
48387                                     callback.apply(socket, args);
48388                             });
48389                         });
48390                     };
48391                     return WebSocket;
48392                 })();
48393                 services.WebSocket = WebSocket;
48394             })(services = app.services || (app.services = {}));
48395         })(app || (app = {}));
48396         var app;
48397         (function (app) {
48398             var directives;
48399             (function (directives) {
48400                 var Command = (function () {
48401                     function Command() {
48402                         this.restrict = 'E';
48403                         this.replace = true;
48404                         this.scope = true;
48405                         this.controller = 'commandController';
48406                         this.controllerAs = 'ctrl';
48407                         this.bindToController = {
48408                             index: '=',
48409                             name: '=',
48410                             remove: '&',
48411                             list: '='
48412                         };
48413                         this.templateUrl = 'templates/command.html';
48414                     }
48415                     Command.Factory = function () {
48416                         var directive = function () {
48417                             return new Command();
48418                         };
48419                         directive.$inject = [];
48420                         return directive;
48421                     };
48422                     return Command;
48423                 })();
48424                 directives.Command = Command;
48425                 var CommandController = (function () {
48426                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
48427                         this.APIEndPoint = APIEndPoint;
48428                         this.$scope = $scope;
48429                         this.MyModal = MyModal;
48430                         this.WebSocket = WebSocket;
48431                         this.$window = $window;
48432                         this.$rootScope = $rootScope;
48433                         var controller = this;
48434                         this.APIEndPoint
48435                             .getOptionControlFile(this.name)
48436                             .$promise
48437                             .then(function (result) {
48438                             controller.options = result.info;
48439                         });
48440                         this.APIEndPoint
48441                             .getDirectories()
48442                             .$promise
48443                             .then(function (result) {
48444                             controller.dirs = result.info;
48445                         });
48446                         this.heading = "[" + this.index + "]: dcdFilePrint";
48447                         this.isOpen = true;
48448                         this.$scope.$on('close', function () {
48449                             controller.isOpen = false;
48450                         });
48451                         function guid() {
48452                             function s4() {
48453                                 return Math.floor((1 + Math.random()) * 0x10000)
48454                                     .toString(16)
48455                                     .substring(1);
48456                             }
48457                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
48458                                 s4() + '-' + s4() + s4() + s4();
48459                         }
48460                         var uuid = guid();
48461                     }
48462                     CommandController.prototype.submit = function () {
48463                         var opt = [];
48464                         angular.forEach(this.options, function (option) {
48465                             var obj = {
48466                                 name: option.option,
48467                                 arguments: []
48468                             };
48469                             angular.forEach(option.arg, function (arg) {
48470                                 if (arg.input) {
48471                                     if (typeof arg.input === 'object') {
48472                                         obj.arguments.push(arg.input.name);
48473                                     }
48474                                     else {
48475                                         obj.arguments.push(arg.input);
48476                                     }
48477                                 }
48478                             });
48479                             if (obj.arguments.length > 0) {
48480                                 opt.push(obj);
48481                             }
48482                         });
48483                         var execObj = {
48484                             command: this.name,
48485                             workspace: this.workspace.fileId,
48486                             options: opt
48487                         };
48488                         this.APIEndPoint
48489                             .execute(JSON.stringify(execObj))
48490                             .then(function (result) {
48491                             console.log(result);
48492                         });
48493                     };
48494                     CommandController.prototype.removeMySelf = function (index) {
48495                         this.$scope.$destroy();
48496                         this.remove()(index, this.list);
48497                     };
48498                     CommandController.prototype.reloadFiles = function () {
48499                         var _this = this;
48500                         var fileId = this.workspace.fileId;
48501                         this.APIEndPoint
48502                             .getFiles(fileId)
48503                             .$promise
48504                             .then(function (result) {
48505                             var status = result.status;
48506                             if (status === 'success') {
48507                                 _this.files = result.info;
48508                             }
48509                             else {
48510                                 console.log(result.message);
48511                             }
48512                         });
48513                     };
48514                     CommandController.prototype.debug = function () {
48515                         console.log(this.$rootScope);
48516                         var div = angular.element(this.$window.document).find("div");
48517                         var consoleTag;
48518                         var parametersTag;
48519                         angular.forEach(div, function (v) {
48520                             if (v.className === "panel-body console") {
48521                                 consoleTag = v;
48522                             }
48523                             else if (v.className === "row parameters-console") {
48524                                 parametersTag = v;
48525                             }
48526                         });
48527                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
48528                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
48529                         consoleTag.style.height = consoleHeight;
48530                         consoleTag.style.width = consoleWidth;
48531                     };
48532                     CommandController.prototype.help = function () {
48533                         this.APIEndPoint
48534                             .help(this.name)
48535                             .then(function (result) {
48536                             console.log(result);
48537                         });
48538                     };
48539                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
48540                     return CommandController;
48541                 })();
48542                 directives.CommandController = CommandController;
48543             })(directives = app.directives || (app.directives = {}));
48544         })(app || (app = {}));
48545         var app;
48546         (function (app) {
48547             var directives;
48548             (function (directives) {
48549                 var HeaderMenu = (function () {
48550                     function HeaderMenu() {
48551                         this.restrict = 'E';
48552                         this.replace = true;
48553                         this.templateUrl = 'templates/header-menu.html';
48554                         this.controller = 'HeaderMenuController';
48555                         this.controllerAs = 'hmc';
48556                         this.scope = true;
48557                     }
48558                     HeaderMenu.Factory = function () {
48559                         var directive = function () {
48560                             return new HeaderMenu();
48561                         };
48562                         return directive;
48563                     };
48564                     return HeaderMenu;
48565                 })();
48566                 directives.HeaderMenu = HeaderMenu;
48567                 var HeaderMenuController = (function () {
48568                     function HeaderMenuController($state) {
48569                         this.$state = $state;
48570                         this.isExecution = this.$state.current.name === 'execution';
48571                         this.isWorkspace = this.$state.current.name === 'workspace';
48572                         this.isHistory = this.$state.current.name === 'history';
48573                     }
48574                     HeaderMenuController.prototype.transit = function (state) {
48575                         this.$state.go(state);
48576                     };
48577                     HeaderMenuController.$inject = ['$state'];
48578                     return HeaderMenuController;
48579                 })();
48580                 directives.HeaderMenuController = HeaderMenuController;
48581             })(directives = app.directives || (app.directives = {}));
48582         })(app || (app = {}));
48583         var app;
48584         (function (app) {
48585             var directives;
48586             (function (directives) {
48587                 var Option = (function () {
48588                     function Option() {
48589                         this.restrict = 'E';
48590                         this.replace = true;
48591                         this.controller = 'optionController';
48592                         this.bindToController = {
48593                             info: '=',
48594                             files: '='
48595                         };
48596                         this.scope = true;
48597                         this.templateUrl = 'templates/option.html';
48598                         this.controllerAs = 'ctrl';
48599                     }
48600                     Option.Factory = function () {
48601                         var directive = function () {
48602                             return new Option();
48603                         };
48604                         directive.$inject = [];
48605                         return directive;
48606                     };
48607                     return Option;
48608                 })();
48609                 directives.Option = Option;
48610                 var OptionController = (function () {
48611                     function OptionController() {
48612                         var controller = this;
48613                         angular.forEach(controller.info.arg, function (arg) {
48614                             if (arg.initialValue) {
48615                                 if (arg.formType === 'number') {
48616                                     arg.input = parseInt(arg.initialValue);
48617                                 }
48618                                 else {
48619                                     arg.input = arg.initialValue;
48620                                 }
48621                             }
48622                         });
48623                     }
48624                     OptionController.$inject = [];
48625                     return OptionController;
48626                 })();
48627                 directives.OptionController = OptionController;
48628             })(directives = app.directives || (app.directives = {}));
48629         })(app || (app = {}));
48630         var app;
48631         (function (app) {
48632             var directives;
48633             (function (directives) {
48634                 var Directory = (function () {
48635                     function Directory() {
48636                         this.restrict = 'E';
48637                         this.replace = true;
48638                         this.controller = 'directoryController';
48639                         this.controllerAs = 'ctrl';
48640                         this.bindToController = {
48641                             info: '=',
48642                             add: '&',
48643                             list: '=',
48644                             files: '='
48645                         };
48646                         this.templateUrl = 'templates/directory.html';
48647                     }
48648                     Directory.Factory = function () {
48649                         var directive = function () {
48650                             return new Directory();
48651                         };
48652                         return directive;
48653                     };
48654                     return Directory;
48655                 })();
48656                 directives.Directory = Directory;
48657                 var DirectoryController = (function () {
48658                     function DirectoryController(APIEndPoint, $scope) {
48659                         this.APIEndPoint = APIEndPoint;
48660                         this.$scope = $scope;
48661                         var controller = this;
48662                         this.APIEndPoint
48663                             .getFiles(this.info.fileId)
48664                             .$promise
48665                             .then(function (result) {
48666                             if (result.status === 'success') {
48667                                 controller.files = result.info;
48668                                 angular.forEach(result.info, function (file) {
48669                                     if (file.fileType === '0') {
48670                                         var o = file;
48671                                         if (controller.info.path === '/') {
48672                                             o.path = '/' + file.name;
48673                                         }
48674                                         else {
48675                                             o.path = controller.info.path + '/' + file.name;
48676                                         }
48677                                         controller.add()(o, controller.list);
48678                                     }
48679                                 });
48680                             }
48681                             ;
48682                         });
48683                     }
48684                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
48685                     return DirectoryController;
48686                 })();
48687                 directives.DirectoryController = DirectoryController;
48688             })(directives = app.directives || (app.directives = {}));
48689         })(app || (app = {}));
48690         var app;
48691         (function (app) {
48692             var controllers;
48693             (function (controllers) {
48694                 var Execution = (function () {
48695                     function Execution(MyModal, $scope) {
48696                         this.MyModal = MyModal;
48697                         this.$scope = $scope;
48698                         this.commandInfoList = [];
48699                     }
48700                     ;
48701                     Execution.prototype.add = function () {
48702                         this.$scope.$broadcast('close');
48703                         var commandInfoList = this.commandInfoList;
48704                         var commandInstance = this.MyModal.selectCommand();
48705                         commandInstance
48706                             .result
48707                             .then(function (command) {
48708                             commandInfoList.push(new app.declares.CommandInfo(command));
48709                         });
48710                     };
48711                     Execution.prototype.open = function () {
48712                         var result = this.MyModal.open('SelectCommand');
48713                         console.log(result);
48714                     };
48715                     Execution.prototype.remove = function (index, list) {
48716                         list.splice(index, 1);
48717                     };
48718                     Execution.prototype.close = function () {
48719                         console.log("close");
48720                     };
48721                     Execution.$inject = ['MyModal', '$scope'];
48722                     return Execution;
48723                 })();
48724                 controllers.Execution = Execution;
48725             })(controllers = app.controllers || (app.controllers = {}));
48726         })(app || (app = {}));
48727         var app;
48728         (function (app) {
48729             var controllers;
48730             (function (controllers) {
48731                 var Workspace = (function () {
48732                     function Workspace($scope, APIEndPoint, MyModal) {
48733                         this.$scope = $scope;
48734                         this.APIEndPoint = APIEndPoint;
48735                         this.MyModal = MyModal;
48736                         this.directoryList = [];
48737                         var controller = this;
48738                         var directoryList = this.directoryList;
48739                         var o = {
48740                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
48741                             name: '',
48742                             parentId: '',
48743                             fileType: '',
48744                             createdAt: '',
48745                             updatedAt: '',
48746                             path: '/'
48747                         };
48748                         directoryList.push(o);
48749                     }
48750                     Workspace.prototype.addDirectory = function (info, directoryList) {
48751                         directoryList.push(info);
48752                     };
48753                     Workspace.prototype.debug = function () {
48754                         this.MyModal.preview();
48755                     };
48756                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
48757                     return Workspace;
48758                 })();
48759                 controllers.Workspace = Workspace;
48760             })(controllers = app.controllers || (app.controllers = {}));
48761         })(app || (app = {}));
48762         var app;
48763         (function (app) {
48764             var controllers;
48765             (function (controllers) {
48766                 var History = (function () {
48767                     function History($scope) {
48768                         this.page = "History";
48769                     }
48770                     History.$inject = ['$scope'];
48771                     return History;
48772                 })();
48773                 controllers.History = History;
48774             })(controllers = app.controllers || (app.controllers = {}));
48775         })(app || (app = {}));
48776         var app;
48777         (function (app) {
48778             var controllers;
48779             (function (controllers) {
48780                 var SelectCommand = (function () {
48781                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
48782                         this.APIEndPoint = APIEndPoint;
48783                         this.$modalInstance = $modalInstance;
48784                         var controller = this;
48785                         this.APIEndPoint
48786                             .getTags()
48787                             .$promise.then(function (result) {
48788                             controller.tags = result.info;
48789                         });
48790                         this.APIEndPoint
48791                             .getCommands()
48792                             .$promise.then(function (result) {
48793                             controller.commands = result.info;
48794                         });
48795                         this.currentTag = 'all';
48796                     }
48797                     SelectCommand.prototype.changeTag = function (tag) {
48798                         this.currentTag = tag;
48799                     };
48800                     SelectCommand.prototype.selectCommand = function (command) {
48801                         this.$modalInstance.close(command);
48802                     };
48803                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48804                     return SelectCommand;
48805                 })();
48806                 controllers.SelectCommand = SelectCommand;
48807             })(controllers = app.controllers || (app.controllers = {}));
48808         })(app || (app = {}));
48809         var app;
48810         (function (app) {
48811             var controllers;
48812             (function (controllers) {
48813                 var Preview = (function () {
48814                     function Preview($scope, APIEndPoint, $modalInstance) {
48815                         this.APIEndPoint = APIEndPoint;
48816                         this.$modalInstance = $modalInstance;
48817                         var controller = this;
48818                         console.log('preview');
48819                     }
48820                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48821                     return Preview;
48822                 })();
48823                 controllers.Preview = Preview;
48824             })(controllers = app.controllers || (app.controllers = {}));
48825         })(app || (app = {}));
48826         var filters;
48827         (function (filters) {
48828             function Tag() {
48829                 return function (commands, tag) {
48830                     var result = [];
48831                     angular.forEach(commands, function (command) {
48832                         var flag = false;
48833                         angular.forEach(command.tags, function (value) {
48834                             if (tag === value)
48835                                 flag = true;
48836                         });
48837                         if (flag)
48838                             result.push(command);
48839                     });
48840                     return result;
48841                 };
48842             }
48843             filters.Tag = Tag;
48844         })(filters || (filters = {}));
48845         var app;
48846         (function (app) {
48847             'use strict';
48848             var appName = 'zephyr';
48849             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
48850             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
48851                 $urlRouterProvider.otherwise('/execution');
48852                 $locationProvider.html5Mode({
48853                     enabled: true,
48854                     requireBase: false
48855                 });
48856                 $stateProvider
48857                     .state('execution', {
48858                     url: '/execution',
48859                     templateUrl: 'templates/execution.html',
48860                     controller: 'executionController',
48861                     controllerAs: 'c'
48862                 })
48863                     .state('workspace', {
48864                     url: '/workspace',
48865                     templateUrl: 'templates/workspace.html',
48866                     controller: 'workspaceController',
48867                     controllerAs: 'c'
48868                 })
48869                     .state('history', {
48870                     url: '/history',
48871                     templateUrl: 'templates/history.html',
48872                     controller: 'historyController',
48873                     controllerAs: 'c'
48874                 });
48875             });
48876             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
48877             app.zephyr.service('MyModal', app.services.MyModal);
48878             app.zephyr.service('WebSocket', app.services.WebSocket);
48879             app.zephyr.filter('Tag', filters.Tag);
48880             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
48881             app.zephyr.controller('previewController', app.controllers.Preview);
48882             app.zephyr.controller('executionController', app.controllers.Execution);
48883             app.zephyr.controller('workspaceController', app.controllers.Workspace);
48884             app.zephyr.controller('historyController', app.controllers.History);
48885             app.zephyr.controller('commandController', app.directives.CommandController);
48886             app.zephyr.controller('optionController', app.directives.OptionController);
48887             app.zephyr.controller('directoryController', app.directives.DirectoryController);
48888             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
48889             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
48890             app.zephyr.directive('command', app.directives.Command.Factory());
48891             app.zephyr.directive('option', app.directives.Option.Factory());
48892             app.zephyr.directive('directory', app.directives.Directory.Factory());
48893         })(app || (app = {}));
48894
48895
48896 /***/ },
48897 /* 20 */
48898 /***/ function(module, exports) {
48899
48900         var app;
48901         (function (app) {
48902             var declares;
48903             (function (declares) {
48904                 var CommandInfo = (function () {
48905                     function CommandInfo(name) {
48906                         this.name = name;
48907                     }
48908                     return CommandInfo;
48909                 })();
48910                 declares.CommandInfo = CommandInfo;
48911             })(declares = app.declares || (app.declares = {}));
48912         })(app || (app = {}));
48913         var app;
48914         (function (app) {
48915             var services;
48916             (function (services) {
48917                 var APIEndPoint = (function () {
48918                     function APIEndPoint($resource, $http) {
48919                         this.$resource = $resource;
48920                         this.$http = $http;
48921                     }
48922                     APIEndPoint.prototype.resource = function (endPoint, data) {
48923                         var customAction = {
48924                             method: 'GET',
48925                             isArray: false
48926                         };
48927                         var execute = {
48928                             method: 'POST',
48929                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
48930                         };
48931                         return this.$resource(endPoint, {}, { execute: execute });
48932                     };
48933                     APIEndPoint.prototype.getOptionControlFile = function (command) {
48934                         var endPoint = '/api/v1/optionControlFile/' + command;
48935                         return this.resource(endPoint, {}).get();
48936                     };
48937                     APIEndPoint.prototype.getFiles = function (fileId) {
48938                         var endPoint = '/api/v1/workspace';
48939                         if (fileId) {
48940                             endPoint += '/' + fileId;
48941                         }
48942                         return this.resource(endPoint, {}).get();
48943                     };
48944                     APIEndPoint.prototype.getDirectories = function () {
48945                         var endPoint = '/api/v1/all/workspace/directory';
48946                         return this.resource(endPoint, {}).get();
48947                     };
48948                     APIEndPoint.prototype.getTags = function () {
48949                         var endPoint = '/api/v1/tagList';
48950                         return this.resource(endPoint, {}).get();
48951                     };
48952                     APIEndPoint.prototype.getCommands = function () {
48953                         var endPoint = '/api/v1/commandList';
48954                         return this.resource(endPoint, {}).get();
48955                     };
48956                     APIEndPoint.prototype.execute = function (data) {
48957                         var endPoint = '/api/v1/execution';
48958                         var fd = new FormData();
48959                         fd.append('data', data);
48960                         return this.$http.post(endPoint, fd, {
48961                             headers: { 'Content-Type': undefined },
48962                             transformRequest: angular.identity
48963                         });
48964                     };
48965                     APIEndPoint.prototype.debug = function () {
48966                         var endPoint = '/api/v1/debug';
48967                         return this.$http.get(endPoint);
48968                     };
48969                     APIEndPoint.prototype.help = function (command) {
48970                         var endPoint = '/api/v1/help/' + command;
48971                         return this.$http.get(endPoint);
48972                     };
48973                     return APIEndPoint;
48974                 })();
48975                 services.APIEndPoint = APIEndPoint;
48976             })(services = app.services || (app.services = {}));
48977         })(app || (app = {}));
48978         var app;
48979         (function (app) {
48980             var services;
48981             (function (services) {
48982                 var MyModal = (function () {
48983                     function MyModal($uibModal) {
48984                         this.$uibModal = $uibModal;
48985                         this.modalOption = {
48986                             backdrop: true,
48987                             controller: null,
48988                             templateUrl: null,
48989                             size: null
48990                         };
48991                     }
48992                     MyModal.prototype.open = function (modalName) {
48993                         if (modalName === 'SelectCommand') {
48994                             this.modalOption.templateUrl = 'templates/select-command.html';
48995                             this.modalOption.size = 'lg';
48996                         }
48997                         return this.$uibModal.open(this.modalOption);
48998                     };
48999                     MyModal.prototype.selectCommand = function () {
49000                         this.modalOption.templateUrl = 'templates/select-command.html';
49001                         this.modalOption.controller = 'selectCommandController';
49002                         this.modalOption.controllerAs = 'c';
49003                         this.modalOption.size = 'lg';
49004                         return this.$uibModal.open(this.modalOption);
49005                     };
49006                     MyModal.prototype.preview = function () {
49007                         this.modalOption.templateUrl = 'templates/preview.html';
49008                         this.modalOption.controller = 'previewController';
49009                         this.modalOption.controllerAs = 'c';
49010                         this.modalOption.size = 'lg';
49011                         return this.$uibModal.open(this.modalOption);
49012                     };
49013                     MyModal.$inject = ['$uibModal'];
49014                     return MyModal;
49015                 })();
49016                 services.MyModal = MyModal;
49017             })(services = app.services || (app.services = {}));
49018         })(app || (app = {}));
49019         var app;
49020         (function (app) {
49021             var services;
49022             (function (services) {
49023                 var WebSocket = (function () {
49024                     function WebSocket($rootScope) {
49025                         this.$rootScope = $rootScope;
49026                         this.socket = io.connect();
49027                     }
49028                     WebSocket.prototype.on = function (eventName, callback) {
49029                         var socket = this.socket;
49030                         var rootScope = this.$rootScope;
49031                         socket.on(eventName, function () {
49032                             var args = arguments;
49033                             rootScope.$apply(function () {
49034                                 callback.apply(socket, args);
49035                             });
49036                         });
49037                     };
49038                     WebSocket.prototype.emit = function (eventName, data, callback) {
49039                         var socket = this.socket;
49040                         var rootScope = this.$rootScope;
49041                         this.socket.emit(eventName, data, function () {
49042                             var args = arguments;
49043                             rootScope.$apply(function () {
49044                                 if (callback)
49045                                     callback.apply(socket, args);
49046                             });
49047                         });
49048                     };
49049                     return WebSocket;
49050                 })();
49051                 services.WebSocket = WebSocket;
49052             })(services = app.services || (app.services = {}));
49053         })(app || (app = {}));
49054         var app;
49055         (function (app) {
49056             var directives;
49057             (function (directives) {
49058                 var Command = (function () {
49059                     function Command() {
49060                         this.restrict = 'E';
49061                         this.replace = true;
49062                         this.scope = true;
49063                         this.controller = 'commandController';
49064                         this.controllerAs = 'ctrl';
49065                         this.bindToController = {
49066                             index: '=',
49067                             name: '=',
49068                             remove: '&',
49069                             list: '='
49070                         };
49071                         this.templateUrl = 'templates/command.html';
49072                     }
49073                     Command.Factory = function () {
49074                         var directive = function () {
49075                             return new Command();
49076                         };
49077                         directive.$inject = [];
49078                         return directive;
49079                     };
49080                     return Command;
49081                 })();
49082                 directives.Command = Command;
49083                 var CommandController = (function () {
49084                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
49085                         this.APIEndPoint = APIEndPoint;
49086                         this.$scope = $scope;
49087                         this.MyModal = MyModal;
49088                         this.WebSocket = WebSocket;
49089                         this.$window = $window;
49090                         this.$rootScope = $rootScope;
49091                         var controller = this;
49092                         this.APIEndPoint
49093                             .getOptionControlFile(this.name)
49094                             .$promise
49095                             .then(function (result) {
49096                             controller.options = result.info;
49097                         });
49098                         this.APIEndPoint
49099                             .getDirectories()
49100                             .$promise
49101                             .then(function (result) {
49102                             controller.dirs = result.info;
49103                         });
49104                         this.heading = "[" + this.index + "]: dcdFilePrint";
49105                         this.isOpen = true;
49106                         this.$scope.$on('close', function () {
49107                             controller.isOpen = false;
49108                         });
49109                         function guid() {
49110                             function s4() {
49111                                 return Math.floor((1 + Math.random()) * 0x10000)
49112                                     .toString(16)
49113                                     .substring(1);
49114                             }
49115                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
49116                                 s4() + '-' + s4() + s4() + s4();
49117                         }
49118                         var uuid = guid();
49119                     }
49120                     CommandController.prototype.submit = function () {
49121                         var opt = [];
49122                         angular.forEach(this.options, function (option) {
49123                             var obj = {
49124                                 name: option.option,
49125                                 arguments: []
49126                             };
49127                             angular.forEach(option.arg, function (arg) {
49128                                 if (arg.input) {
49129                                     if (typeof arg.input === 'object') {
49130                                         obj.arguments.push(arg.input.name);
49131                                     }
49132                                     else {
49133                                         obj.arguments.push(arg.input);
49134                                     }
49135                                 }
49136                             });
49137                             if (obj.arguments.length > 0) {
49138                                 opt.push(obj);
49139                             }
49140                         });
49141                         var execObj = {
49142                             command: this.name,
49143                             workspace: this.workspace.fileId,
49144                             options: opt
49145                         };
49146                         this.APIEndPoint
49147                             .execute(JSON.stringify(execObj))
49148                             .then(function (result) {
49149                             console.log(result);
49150                         });
49151                     };
49152                     CommandController.prototype.removeMySelf = function (index) {
49153                         this.$scope.$destroy();
49154                         this.remove()(index, this.list);
49155                     };
49156                     CommandController.prototype.reloadFiles = function () {
49157                         var _this = this;
49158                         var fileId = this.workspace.fileId;
49159                         this.APIEndPoint
49160                             .getFiles(fileId)
49161                             .$promise
49162                             .then(function (result) {
49163                             var status = result.status;
49164                             if (status === 'success') {
49165                                 _this.files = result.info;
49166                             }
49167                             else {
49168                                 console.log(result.message);
49169                             }
49170                         });
49171                     };
49172                     CommandController.prototype.debug = function () {
49173                         console.log(this.$rootScope);
49174                         var div = angular.element(this.$window.document).find("div");
49175                         var consoleTag;
49176                         var parametersTag;
49177                         angular.forEach(div, function (v) {
49178                             if (v.className === "panel-body console") {
49179                                 consoleTag = v;
49180                             }
49181                             else if (v.className === "row parameters-console") {
49182                                 parametersTag = v;
49183                             }
49184                         });
49185                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
49186                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
49187                         consoleTag.style.height = consoleHeight;
49188                         consoleTag.style.width = consoleWidth;
49189                     };
49190                     CommandController.prototype.help = function () {
49191                         this.APIEndPoint
49192                             .help(this.name)
49193                             .then(function (result) {
49194                             console.log(result);
49195                         });
49196                     };
49197                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
49198                     return CommandController;
49199                 })();
49200                 directives.CommandController = CommandController;
49201             })(directives = app.directives || (app.directives = {}));
49202         })(app || (app = {}));
49203         var app;
49204         (function (app) {
49205             var directives;
49206             (function (directives) {
49207                 var HeaderMenu = (function () {
49208                     function HeaderMenu() {
49209                         this.restrict = 'E';
49210                         this.replace = true;
49211                         this.templateUrl = 'templates/header-menu.html';
49212                         this.controller = 'HeaderMenuController';
49213                         this.controllerAs = 'hmc';
49214                         this.scope = true;
49215                     }
49216                     HeaderMenu.Factory = function () {
49217                         var directive = function () {
49218                             return new HeaderMenu();
49219                         };
49220                         return directive;
49221                     };
49222                     return HeaderMenu;
49223                 })();
49224                 directives.HeaderMenu = HeaderMenu;
49225                 var HeaderMenuController = (function () {
49226                     function HeaderMenuController($state) {
49227                         this.$state = $state;
49228                         this.isExecution = this.$state.current.name === 'execution';
49229                         this.isWorkspace = this.$state.current.name === 'workspace';
49230                         this.isHistory = this.$state.current.name === 'history';
49231                     }
49232                     HeaderMenuController.prototype.transit = function (state) {
49233                         this.$state.go(state);
49234                     };
49235                     HeaderMenuController.$inject = ['$state'];
49236                     return HeaderMenuController;
49237                 })();
49238                 directives.HeaderMenuController = HeaderMenuController;
49239             })(directives = app.directives || (app.directives = {}));
49240         })(app || (app = {}));
49241         var app;
49242         (function (app) {
49243             var directives;
49244             (function (directives) {
49245                 var Option = (function () {
49246                     function Option() {
49247                         this.restrict = 'E';
49248                         this.replace = true;
49249                         this.controller = 'optionController';
49250                         this.bindToController = {
49251                             info: '=',
49252                             files: '='
49253                         };
49254                         this.scope = true;
49255                         this.templateUrl = 'templates/option.html';
49256                         this.controllerAs = 'ctrl';
49257                     }
49258                     Option.Factory = function () {
49259                         var directive = function () {
49260                             return new Option();
49261                         };
49262                         directive.$inject = [];
49263                         return directive;
49264                     };
49265                     return Option;
49266                 })();
49267                 directives.Option = Option;
49268                 var OptionController = (function () {
49269                     function OptionController() {
49270                         var controller = this;
49271                         angular.forEach(controller.info.arg, function (arg) {
49272                             if (arg.initialValue) {
49273                                 if (arg.formType === 'number') {
49274                                     arg.input = parseInt(arg.initialValue);
49275                                 }
49276                                 else {
49277                                     arg.input = arg.initialValue;
49278                                 }
49279                             }
49280                         });
49281                     }
49282                     OptionController.$inject = [];
49283                     return OptionController;
49284                 })();
49285                 directives.OptionController = OptionController;
49286             })(directives = app.directives || (app.directives = {}));
49287         })(app || (app = {}));
49288         var app;
49289         (function (app) {
49290             var directives;
49291             (function (directives) {
49292                 var Directory = (function () {
49293                     function Directory() {
49294                         this.restrict = 'E';
49295                         this.replace = true;
49296                         this.controller = 'directoryController';
49297                         this.controllerAs = 'ctrl';
49298                         this.bindToController = {
49299                             info: '=',
49300                             add: '&',
49301                             list: '=',
49302                             files: '='
49303                         };
49304                         this.templateUrl = 'templates/directory.html';
49305                     }
49306                     Directory.Factory = function () {
49307                         var directive = function () {
49308                             return new Directory();
49309                         };
49310                         return directive;
49311                     };
49312                     return Directory;
49313                 })();
49314                 directives.Directory = Directory;
49315                 var DirectoryController = (function () {
49316                     function DirectoryController(APIEndPoint, $scope) {
49317                         this.APIEndPoint = APIEndPoint;
49318                         this.$scope = $scope;
49319                         var controller = this;
49320                         this.APIEndPoint
49321                             .getFiles(this.info.fileId)
49322                             .$promise
49323                             .then(function (result) {
49324                             if (result.status === 'success') {
49325                                 controller.files = result.info;
49326                                 angular.forEach(result.info, function (file) {
49327                                     if (file.fileType === '0') {
49328                                         var o = file;
49329                                         if (controller.info.path === '/') {
49330                                             o.path = '/' + file.name;
49331                                         }
49332                                         else {
49333                                             o.path = controller.info.path + '/' + file.name;
49334                                         }
49335                                         controller.add()(o, controller.list);
49336                                     }
49337                                 });
49338                             }
49339                             ;
49340                         });
49341                     }
49342                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
49343                     return DirectoryController;
49344                 })();
49345                 directives.DirectoryController = DirectoryController;
49346             })(directives = app.directives || (app.directives = {}));
49347         })(app || (app = {}));
49348         var app;
49349         (function (app) {
49350             var controllers;
49351             (function (controllers) {
49352                 var Execution = (function () {
49353                     function Execution(MyModal, $scope) {
49354                         this.MyModal = MyModal;
49355                         this.$scope = $scope;
49356                         this.commandInfoList = [];
49357                     }
49358                     ;
49359                     Execution.prototype.add = function () {
49360                         this.$scope.$broadcast('close');
49361                         var commandInfoList = this.commandInfoList;
49362                         var commandInstance = this.MyModal.selectCommand();
49363                         commandInstance
49364                             .result
49365                             .then(function (command) {
49366                             commandInfoList.push(new app.declares.CommandInfo(command));
49367                         });
49368                     };
49369                     Execution.prototype.open = function () {
49370                         var result = this.MyModal.open('SelectCommand');
49371                         console.log(result);
49372                     };
49373                     Execution.prototype.remove = function (index, list) {
49374                         list.splice(index, 1);
49375                     };
49376                     Execution.prototype.close = function () {
49377                         console.log("close");
49378                     };
49379                     Execution.$inject = ['MyModal', '$scope'];
49380                     return Execution;
49381                 })();
49382                 controllers.Execution = Execution;
49383             })(controllers = app.controllers || (app.controllers = {}));
49384         })(app || (app = {}));
49385         var app;
49386         (function (app) {
49387             var controllers;
49388             (function (controllers) {
49389                 var Workspace = (function () {
49390                     function Workspace($scope, APIEndPoint, MyModal) {
49391                         this.$scope = $scope;
49392                         this.APIEndPoint = APIEndPoint;
49393                         this.MyModal = MyModal;
49394                         this.directoryList = [];
49395                         var controller = this;
49396                         var directoryList = this.directoryList;
49397                         var o = {
49398                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
49399                             name: '',
49400                             parentId: '',
49401                             fileType: '',
49402                             createdAt: '',
49403                             updatedAt: '',
49404                             path: '/'
49405                         };
49406                         directoryList.push(o);
49407                     }
49408                     Workspace.prototype.addDirectory = function (info, directoryList) {
49409                         directoryList.push(info);
49410                     };
49411                     Workspace.prototype.debug = function () {
49412                         this.MyModal.preview();
49413                     };
49414                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
49415                     return Workspace;
49416                 })();
49417                 controllers.Workspace = Workspace;
49418             })(controllers = app.controllers || (app.controllers = {}));
49419         })(app || (app = {}));
49420         var app;
49421         (function (app) {
49422             var controllers;
49423             (function (controllers) {
49424                 var History = (function () {
49425                     function History($scope) {
49426                         this.page = "History";
49427                     }
49428                     History.$inject = ['$scope'];
49429                     return History;
49430                 })();
49431                 controllers.History = History;
49432             })(controllers = app.controllers || (app.controllers = {}));
49433         })(app || (app = {}));
49434         var app;
49435         (function (app) {
49436             var controllers;
49437             (function (controllers) {
49438                 var SelectCommand = (function () {
49439                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
49440                         this.APIEndPoint = APIEndPoint;
49441                         this.$modalInstance = $modalInstance;
49442                         var controller = this;
49443                         this.APIEndPoint
49444                             .getTags()
49445                             .$promise.then(function (result) {
49446                             controller.tags = result.info;
49447                         });
49448                         this.APIEndPoint
49449                             .getCommands()
49450                             .$promise.then(function (result) {
49451                             controller.commands = result.info;
49452                         });
49453                         this.currentTag = 'all';
49454                     }
49455                     SelectCommand.prototype.changeTag = function (tag) {
49456                         this.currentTag = tag;
49457                     };
49458                     SelectCommand.prototype.selectCommand = function (command) {
49459                         this.$modalInstance.close(command);
49460                     };
49461                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
49462                     return SelectCommand;
49463                 })();
49464                 controllers.SelectCommand = SelectCommand;
49465             })(controllers = app.controllers || (app.controllers = {}));
49466         })(app || (app = {}));
49467         var app;
49468         (function (app) {
49469             var controllers;
49470             (function (controllers) {
49471                 var Preview = (function () {
49472                     function Preview($scope, APIEndPoint, $modalInstance) {
49473                         this.APIEndPoint = APIEndPoint;
49474                         this.$modalInstance = $modalInstance;
49475                         var controller = this;
49476                         console.log('preview');
49477                     }
49478                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
49479                     return Preview;
49480                 })();
49481                 controllers.Preview = Preview;
49482             })(controllers = app.controllers || (app.controllers = {}));
49483         })(app || (app = {}));
49484         var filters;
49485         (function (filters) {
49486             function Tag() {
49487                 return function (commands, tag) {
49488                     var result = [];
49489                     angular.forEach(commands, function (command) {
49490                         var flag = false;
49491                         angular.forEach(command.tags, function (value) {
49492                             if (tag === value)
49493                                 flag = true;
49494                         });
49495                         if (flag)
49496                             result.push(command);
49497                     });
49498                     return result;
49499                 };
49500             }
49501             filters.Tag = Tag;
49502         })(filters || (filters = {}));
49503         var app;
49504         (function (app) {
49505             'use strict';
49506             var appName = 'zephyr';
49507             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
49508             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
49509                 $urlRouterProvider.otherwise('/execution');
49510                 $locationProvider.html5Mode({
49511                     enabled: true,
49512                     requireBase: false
49513                 });
49514                 $stateProvider
49515                     .state('execution', {
49516                     url: '/execution',
49517                     templateUrl: 'templates/execution.html',
49518                     controller: 'executionController',
49519                     controllerAs: 'c'
49520                 })
49521                     .state('workspace', {
49522                     url: '/workspace',
49523                     templateUrl: 'templates/workspace.html',
49524                     controller: 'workspaceController',
49525                     controllerAs: 'c'
49526                 })
49527                     .state('history', {
49528                     url: '/history',
49529                     templateUrl: 'templates/history.html',
49530                     controller: 'historyController',
49531                     controllerAs: 'c'
49532                 });
49533             });
49534             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
49535             app.zephyr.service('MyModal', app.services.MyModal);
49536             app.zephyr.service('WebSocket', app.services.WebSocket);
49537             app.zephyr.filter('Tag', filters.Tag);
49538             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
49539             app.zephyr.controller('previewController', app.controllers.Preview);
49540             app.zephyr.controller('executionController', app.controllers.Execution);
49541             app.zephyr.controller('workspaceController', app.controllers.Workspace);
49542             app.zephyr.controller('historyController', app.controllers.History);
49543             app.zephyr.controller('commandController', app.directives.CommandController);
49544             app.zephyr.controller('optionController', app.directives.OptionController);
49545             app.zephyr.controller('directoryController', app.directives.DirectoryController);
49546             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
49547             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
49548             app.zephyr.directive('command', app.directives.Command.Factory());
49549             app.zephyr.directive('option', app.directives.Option.Factory());
49550             app.zephyr.directive('directory', app.directives.Directory.Factory());
49551         })(app || (app = {}));
49552
49553
49554 /***/ },
49555 /* 21 */
49556 /***/ function(module, exports) {
49557
49558         var app;
49559         (function (app) {
49560             var declares;
49561             (function (declares) {
49562                 var CommandInfo = (function () {
49563                     function CommandInfo(name) {
49564                         this.name = name;
49565                     }
49566                     return CommandInfo;
49567                 })();
49568                 declares.CommandInfo = CommandInfo;
49569             })(declares = app.declares || (app.declares = {}));
49570         })(app || (app = {}));
49571         var app;
49572         (function (app) {
49573             var services;
49574             (function (services) {
49575                 var APIEndPoint = (function () {
49576                     function APIEndPoint($resource, $http) {
49577                         this.$resource = $resource;
49578                         this.$http = $http;
49579                     }
49580                     APIEndPoint.prototype.resource = function (endPoint, data) {
49581                         var customAction = {
49582                             method: 'GET',
49583                             isArray: false
49584                         };
49585                         var execute = {
49586                             method: 'POST',
49587                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
49588                         };
49589                         return this.$resource(endPoint, {}, { execute: execute });
49590                     };
49591                     APIEndPoint.prototype.getOptionControlFile = function (command) {
49592                         var endPoint = '/api/v1/optionControlFile/' + command;
49593                         return this.resource(endPoint, {}).get();
49594                     };
49595                     APIEndPoint.prototype.getFiles = function (fileId) {
49596                         var endPoint = '/api/v1/workspace';
49597                         if (fileId) {
49598                             endPoint += '/' + fileId;
49599                         }
49600                         return this.resource(endPoint, {}).get();
49601                     };
49602                     APIEndPoint.prototype.getDirectories = function () {
49603                         var endPoint = '/api/v1/all/workspace/directory';
49604                         return this.resource(endPoint, {}).get();
49605                     };
49606                     APIEndPoint.prototype.getTags = function () {
49607                         var endPoint = '/api/v1/tagList';
49608                         return this.resource(endPoint, {}).get();
49609                     };
49610                     APIEndPoint.prototype.getCommands = function () {
49611                         var endPoint = '/api/v1/commandList';
49612                         return this.resource(endPoint, {}).get();
49613                     };
49614                     APIEndPoint.prototype.execute = function (data) {
49615                         var endPoint = '/api/v1/execution';
49616                         var fd = new FormData();
49617                         fd.append('data', data);
49618                         return this.$http.post(endPoint, fd, {
49619                             headers: { 'Content-Type': undefined },
49620                             transformRequest: angular.identity
49621                         });
49622                     };
49623                     APIEndPoint.prototype.debug = function () {
49624                         var endPoint = '/api/v1/debug';
49625                         return this.$http.get(endPoint);
49626                     };
49627                     APIEndPoint.prototype.help = function (command) {
49628                         var endPoint = '/api/v1/help/' + command;
49629                         return this.$http.get(endPoint);
49630                     };
49631                     return APIEndPoint;
49632                 })();
49633                 services.APIEndPoint = APIEndPoint;
49634             })(services = app.services || (app.services = {}));
49635         })(app || (app = {}));
49636         var app;
49637         (function (app) {
49638             var services;
49639             (function (services) {
49640                 var MyModal = (function () {
49641                     function MyModal($uibModal) {
49642                         this.$uibModal = $uibModal;
49643                         this.modalOption = {
49644                             backdrop: true,
49645                             controller: null,
49646                             templateUrl: null,
49647                             size: null
49648                         };
49649                     }
49650                     MyModal.prototype.open = function (modalName) {
49651                         if (modalName === 'SelectCommand') {
49652                             this.modalOption.templateUrl = 'templates/select-command.html';
49653                             this.modalOption.size = 'lg';
49654                         }
49655                         return this.$uibModal.open(this.modalOption);
49656                     };
49657                     MyModal.prototype.selectCommand = function () {
49658                         this.modalOption.templateUrl = 'templates/select-command.html';
49659                         this.modalOption.controller = 'selectCommandController';
49660                         this.modalOption.controllerAs = 'c';
49661                         this.modalOption.size = 'lg';
49662                         return this.$uibModal.open(this.modalOption);
49663                     };
49664                     MyModal.prototype.preview = function () {
49665                         this.modalOption.templateUrl = 'templates/preview.html';
49666                         this.modalOption.controller = 'previewController';
49667                         this.modalOption.controllerAs = 'c';
49668                         this.modalOption.size = 'lg';
49669                         return this.$uibModal.open(this.modalOption);
49670                     };
49671                     MyModal.$inject = ['$uibModal'];
49672                     return MyModal;
49673                 })();
49674                 services.MyModal = MyModal;
49675             })(services = app.services || (app.services = {}));
49676         })(app || (app = {}));
49677         var app;
49678         (function (app) {
49679             var services;
49680             (function (services) {
49681                 var WebSocket = (function () {
49682                     function WebSocket($rootScope) {
49683                         this.$rootScope = $rootScope;
49684                         this.socket = io.connect();
49685                     }
49686                     WebSocket.prototype.on = function (eventName, callback) {
49687                         var socket = this.socket;
49688                         var rootScope = this.$rootScope;
49689                         socket.on(eventName, function () {
49690                             var args = arguments;
49691                             rootScope.$apply(function () {
49692                                 callback.apply(socket, args);
49693                             });
49694                         });
49695                     };
49696                     WebSocket.prototype.emit = function (eventName, data, callback) {
49697                         var socket = this.socket;
49698                         var rootScope = this.$rootScope;
49699                         this.socket.emit(eventName, data, function () {
49700                             var args = arguments;
49701                             rootScope.$apply(function () {
49702                                 if (callback)
49703                                     callback.apply(socket, args);
49704                             });
49705                         });
49706                     };
49707                     return WebSocket;
49708                 })();
49709                 services.WebSocket = WebSocket;
49710             })(services = app.services || (app.services = {}));
49711         })(app || (app = {}));
49712         var app;
49713         (function (app) {
49714             var directives;
49715             (function (directives) {
49716                 var Command = (function () {
49717                     function Command() {
49718                         this.restrict = 'E';
49719                         this.replace = true;
49720                         this.scope = true;
49721                         this.controller = 'commandController';
49722                         this.controllerAs = 'ctrl';
49723                         this.bindToController = {
49724                             index: '=',
49725                             name: '=',
49726                             remove: '&',
49727                             list: '='
49728                         };
49729                         this.templateUrl = 'templates/command.html';
49730                     }
49731                     Command.Factory = function () {
49732                         var directive = function () {
49733                             return new Command();
49734                         };
49735                         directive.$inject = [];
49736                         return directive;
49737                     };
49738                     return Command;
49739                 })();
49740                 directives.Command = Command;
49741                 var CommandController = (function () {
49742                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope) {
49743                         this.APIEndPoint = APIEndPoint;
49744                         this.$scope = $scope;
49745                         this.MyModal = MyModal;
49746                         this.WebSocket = WebSocket;
49747                         this.$window = $window;
49748                         this.$rootScope = $rootScope;
49749                         var controller = this;
49750                         this.APIEndPoint
49751                             .getOptionControlFile(this.name)
49752                             .$promise
49753                             .then(function (result) {
49754                             controller.options = result.info;
49755                         });
49756                         this.APIEndPoint
49757                             .getDirectories()
49758                             .$promise
49759                             .then(function (result) {
49760                             controller.dirs = result.info;
49761                         });
49762                         this.heading = "[" + this.index + "]: dcdFilePrint";
49763                         this.isOpen = true;
49764                         this.$scope.$on('close', function () {
49765                             controller.isOpen = false;
49766                         });
49767                         function guid() {
49768                             function s4() {
49769                                 return Math.floor((1 + Math.random()) * 0x10000)
49770                                     .toString(16)
49771                                     .substring(1);
49772                             }
49773                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
49774                                 s4() + '-' + s4() + s4() + s4();
49775                         }
49776                         var uuid = guid();
49777                     }
49778                     CommandController.prototype.submit = function () {
49779                         var opt = [];
49780                         angular.forEach(this.options, function (option) {
49781                             var obj = {
49782                                 name: option.option,
49783                                 arguments: []
49784                             };
49785                             angular.forEach(option.arg, function (arg) {
49786                                 if (arg.input) {
49787                                     if (typeof arg.input === 'object') {
49788                                         obj.arguments.push(arg.input.name);
49789                                     }
49790                                     else {
49791                                         obj.arguments.push(arg.input);
49792                                     }
49793                                 }
49794                             });
49795                             if (obj.arguments.length > 0) {
49796                                 opt.push(obj);
49797                             }
49798                         });
49799                         var execObj = {
49800                             command: this.name,
49801                             workspace: this.workspace.fileId,
49802                             options: opt
49803                         };
49804                         this.APIEndPoint
49805                             .execute(JSON.stringify(execObj))
49806                             .then(function (result) {
49807                             console.log(result);
49808                         });
49809                     };
49810                     CommandController.prototype.removeMySelf = function (index) {
49811                         this.$scope.$destroy();
49812                         this.remove()(index, this.list);
49813                     };
49814                     CommandController.prototype.reloadFiles = function () {
49815                         var _this = this;
49816                         var fileId = this.workspace.fileId;
49817                         this.APIEndPoint
49818                             .getFiles(fileId)
49819                             .$promise
49820                             .then(function (result) {
49821                             var status = result.status;
49822                             if (status === 'success') {
49823                                 _this.files = result.info;
49824                             }
49825                             else {
49826                                 console.log(result.message);
49827                             }
49828                         });
49829                     };
49830                     CommandController.prototype.debug = function () {
49831                         console.log(this.$rootScope);
49832                         var div = angular.element(this.$window.document).find("div");
49833                         var consoleTag;
49834                         var parametersTag;
49835                         angular.forEach(div, function (v) {
49836                             if (v.className === "panel-body console") {
49837                                 consoleTag = v;
49838                             }
49839                             else if (v.className === "row parameters-console") {
49840                                 parametersTag = v;
49841                             }
49842                         });
49843                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
49844                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
49845                         consoleTag.style.height = consoleHeight;
49846                         consoleTag.style.width = consoleWidth;
49847                     };
49848                     CommandController.prototype.help = function () {
49849                         this.APIEndPoint
49850                             .help(this.name)
49851                             .then(function (result) {
49852                             console.log(result);
49853                         });
49854                     };
49855                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope'];
49856                     return CommandController;
49857                 })();
49858                 directives.CommandController = CommandController;
49859             })(directives = app.directives || (app.directives = {}));
49860         })(app || (app = {}));
49861         var app;
49862         (function (app) {
49863             var directives;
49864             (function (directives) {
49865                 var HeaderMenu = (function () {
49866                     function HeaderMenu() {
49867                         this.restrict = 'E';
49868                         this.replace = true;
49869                         this.templateUrl = 'templates/header-menu.html';
49870                         this.controller = 'HeaderMenuController';
49871                         this.controllerAs = 'hmc';
49872                         this.scope = true;
49873                     }
49874                     HeaderMenu.Factory = function () {
49875                         var directive = function () {
49876                             return new HeaderMenu();
49877                         };
49878                         return directive;
49879                     };
49880                     return HeaderMenu;
49881                 })();
49882                 directives.HeaderMenu = HeaderMenu;
49883                 var HeaderMenuController = (function () {
49884                     function HeaderMenuController($state) {
49885                         this.$state = $state;
49886                         this.isExecution = this.$state.current.name === 'execution';
49887                         this.isWorkspace = this.$state.current.name === 'workspace';
49888                         this.isHistory = this.$state.current.name === 'history';
49889                     }
49890                     HeaderMenuController.prototype.transit = function (state) {
49891                         this.$state.go(state);
49892                     };
49893                     HeaderMenuController.$inject = ['$state'];
49894                     return HeaderMenuController;
49895                 })();
49896                 directives.HeaderMenuController = HeaderMenuController;
49897             })(directives = app.directives || (app.directives = {}));
49898         })(app || (app = {}));
49899         var app;
49900         (function (app) {
49901             var directives;
49902             (function (directives) {
49903                 var Option = (function () {
49904                     function Option() {
49905                         this.restrict = 'E';
49906                         this.replace = true;
49907                         this.controller = 'optionController';
49908                         this.bindToController = {
49909                             info: '=',
49910                             files: '='
49911                         };
49912                         this.scope = true;
49913                         this.templateUrl = 'templates/option.html';
49914                         this.controllerAs = 'ctrl';
49915                     }
49916                     Option.Factory = function () {
49917                         var directive = function () {
49918                             return new Option();
49919                         };
49920                         directive.$inject = [];
49921                         return directive;
49922                     };
49923                     return Option;
49924                 })();
49925                 directives.Option = Option;
49926                 var OptionController = (function () {
49927                     function OptionController() {
49928                         var controller = this;
49929                         angular.forEach(controller.info.arg, function (arg) {
49930                             if (arg.initialValue) {
49931                                 if (arg.formType === 'number') {
49932                                     arg.input = parseInt(arg.initialValue);
49933                                 }
49934                                 else {
49935                                     arg.input = arg.initialValue;
49936                                 }
49937                             }
49938                         });
49939                     }
49940                     OptionController.$inject = [];
49941                     return OptionController;
49942                 })();
49943                 directives.OptionController = OptionController;
49944             })(directives = app.directives || (app.directives = {}));
49945         })(app || (app = {}));
49946         var app;
49947         (function (app) {
49948             var directives;
49949             (function (directives) {
49950                 var Directory = (function () {
49951                     function Directory() {
49952                         this.restrict = 'E';
49953                         this.replace = true;
49954                         this.controller = 'directoryController';
49955                         this.controllerAs = 'ctrl';
49956                         this.bindToController = {
49957                             info: '=',
49958                             add: '&',
49959                             list: '=',
49960                             files: '='
49961                         };
49962                         this.templateUrl = 'templates/directory.html';
49963                     }
49964                     Directory.Factory = function () {
49965                         var directive = function () {
49966                             return new Directory();
49967                         };
49968                         return directive;
49969                     };
49970                     return Directory;
49971                 })();
49972                 directives.Directory = Directory;
49973                 var DirectoryController = (function () {
49974                     function DirectoryController(APIEndPoint, $scope) {
49975                         this.APIEndPoint = APIEndPoint;
49976                         this.$scope = $scope;
49977                         var controller = this;
49978                         this.APIEndPoint
49979                             .getFiles(this.info.fileId)
49980                             .$promise
49981                             .then(function (result) {
49982                             if (result.status === 'success') {
49983                                 controller.files = result.info;
49984                                 angular.forEach(result.info, function (file) {
49985                                     if (file.fileType === '0') {
49986                                         var o = file;
49987                                         if (controller.info.path === '/') {
49988                                             o.path = '/' + file.name;
49989                                         }
49990                                         else {
49991                                             o.path = controller.info.path + '/' + file.name;
49992                                         }
49993                                         controller.add()(o, controller.list);
49994                                     }
49995                                 });
49996                             }
49997                             ;
49998                         });
49999                     }
50000                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
50001                     return DirectoryController;
50002                 })();
50003                 directives.DirectoryController = DirectoryController;
50004             })(directives = app.directives || (app.directives = {}));
50005         })(app || (app = {}));
50006         var app;
50007         (function (app) {
50008             var controllers;
50009             (function (controllers) {
50010                 var Execution = (function () {
50011                     function Execution(MyModal, $scope) {
50012                         this.MyModal = MyModal;
50013                         this.$scope = $scope;
50014                         this.commandInfoList = [];
50015                     }
50016                     ;
50017                     Execution.prototype.add = function () {
50018                         this.$scope.$broadcast('close');
50019                         var commandInfoList = this.commandInfoList;
50020                         var commandInstance = this.MyModal.selectCommand();
50021                         commandInstance
50022                             .result
50023                             .then(function (command) {
50024                             commandInfoList.push(new app.declares.CommandInfo(command));
50025                         });
50026                     };
50027                     Execution.prototype.open = function () {
50028                         var result = this.MyModal.open('SelectCommand');
50029                         console.log(result);
50030                     };
50031                     Execution.prototype.remove = function (index, list) {
50032                         list.splice(index, 1);
50033                     };
50034                     Execution.prototype.close = function () {
50035                         console.log("close");
50036                     };
50037                     Execution.$inject = ['MyModal', '$scope'];
50038                     return Execution;
50039                 })();
50040                 controllers.Execution = Execution;
50041             })(controllers = app.controllers || (app.controllers = {}));
50042         })(app || (app = {}));
50043         var app;
50044         (function (app) {
50045             var controllers;
50046             (function (controllers) {
50047                 var Workspace = (function () {
50048                     function Workspace($scope, APIEndPoint, MyModal) {
50049                         this.$scope = $scope;
50050                         this.APIEndPoint = APIEndPoint;
50051                         this.MyModal = MyModal;
50052                         this.directoryList = [];
50053                         var controller = this;
50054                         var directoryList = this.directoryList;
50055                         var o = {
50056                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
50057                             name: '',
50058                             parentId: '',
50059                             fileType: '',
50060                             createdAt: '',
50061                             updatedAt: '',
50062                             path: '/'
50063                         };
50064                         directoryList.push(o);
50065                     }
50066                     Workspace.prototype.addDirectory = function (info, directoryList) {
50067                         directoryList.push(info);
50068                     };
50069                     Workspace.prototype.debug = function () {
50070                         this.MyModal.preview();
50071                     };
50072                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
50073                     return Workspace;
50074                 })();
50075                 controllers.Workspace = Workspace;
50076             })(controllers = app.controllers || (app.controllers = {}));
50077         })(app || (app = {}));
50078         var app;
50079         (function (app) {
50080             var controllers;
50081             (function (controllers) {
50082                 var History = (function () {
50083                     function History($scope) {
50084                         this.page = "History";
50085                     }
50086                     History.$inject = ['$scope'];
50087                     return History;
50088                 })();
50089                 controllers.History = History;
50090             })(controllers = app.controllers || (app.controllers = {}));
50091         })(app || (app = {}));
50092         var app;
50093         (function (app) {
50094             var controllers;
50095             (function (controllers) {
50096                 var SelectCommand = (function () {
50097                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
50098                         this.APIEndPoint = APIEndPoint;
50099                         this.$modalInstance = $modalInstance;
50100                         var controller = this;
50101                         this.APIEndPoint
50102                             .getTags()
50103                             .$promise.then(function (result) {
50104                             controller.tags = result.info;
50105                         });
50106                         this.APIEndPoint
50107                             .getCommands()
50108                             .$promise.then(function (result) {
50109                             controller.commands = result.info;
50110                         });
50111                         this.currentTag = 'all';
50112                     }
50113                     SelectCommand.prototype.changeTag = function (tag) {
50114                         this.currentTag = tag;
50115                     };
50116                     SelectCommand.prototype.selectCommand = function (command) {
50117                         this.$modalInstance.close(command);
50118                     };
50119                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50120                     return SelectCommand;
50121                 })();
50122                 controllers.SelectCommand = SelectCommand;
50123             })(controllers = app.controllers || (app.controllers = {}));
50124         })(app || (app = {}));
50125         var app;
50126         (function (app) {
50127             var controllers;
50128             (function (controllers) {
50129                 var Preview = (function () {
50130                     function Preview($scope, APIEndPoint, $modalInstance) {
50131                         this.APIEndPoint = APIEndPoint;
50132                         this.$modalInstance = $modalInstance;
50133                         var controller = this;
50134                         console.log('preview');
50135                     }
50136                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50137                     return Preview;
50138                 })();
50139                 controllers.Preview = Preview;
50140             })(controllers = app.controllers || (app.controllers = {}));
50141         })(app || (app = {}));
50142         var filters;
50143         (function (filters) {
50144             function Tag() {
50145                 return function (commands, tag) {
50146                     var result = [];
50147                     angular.forEach(commands, function (command) {
50148                         var flag = false;
50149                         angular.forEach(command.tags, function (value) {
50150                             if (tag === value)
50151                                 flag = true;
50152                         });
50153                         if (flag)
50154                             result.push(command);
50155                     });
50156                     return result;
50157                 };
50158             }
50159             filters.Tag = Tag;
50160         })(filters || (filters = {}));
50161         var app;
50162         (function (app) {
50163             'use strict';
50164             var appName = 'zephyr';
50165             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
50166             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
50167                 $urlRouterProvider.otherwise('/execution');
50168                 $locationProvider.html5Mode({
50169                     enabled: true,
50170                     requireBase: false
50171                 });
50172                 $stateProvider
50173                     .state('execution', {
50174                     url: '/execution',
50175                     templateUrl: 'templates/execution.html',
50176                     controller: 'executionController',
50177                     controllerAs: 'c'
50178                 })
50179                     .state('workspace', {
50180                     url: '/workspace',
50181                     templateUrl: 'templates/workspace.html',
50182                     controller: 'workspaceController',
50183                     controllerAs: 'c'
50184                 })
50185                     .state('history', {
50186                     url: '/history',
50187                     templateUrl: 'templates/history.html',
50188                     controller: 'historyController',
50189                     controllerAs: 'c'
50190                 });
50191             });
50192             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
50193             app.zephyr.service('MyModal', app.services.MyModal);
50194             app.zephyr.service('WebSocket', app.services.WebSocket);
50195             app.zephyr.filter('Tag', filters.Tag);
50196             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
50197             app.zephyr.controller('previewController', app.controllers.Preview);
50198             app.zephyr.controller('executionController', app.controllers.Execution);
50199             app.zephyr.controller('workspaceController', app.controllers.Workspace);
50200             app.zephyr.controller('historyController', app.controllers.History);
50201             app.zephyr.controller('commandController', app.directives.CommandController);
50202             app.zephyr.controller('optionController', app.directives.OptionController);
50203             app.zephyr.controller('directoryController', app.directives.DirectoryController);
50204             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
50205             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
50206             app.zephyr.directive('command', app.directives.Command.Factory());
50207             app.zephyr.directive('option', app.directives.Option.Factory());
50208             app.zephyr.directive('directory', app.directives.Directory.Factory());
50209         })(app || (app = {}));
50210
50211
50212 /***/ }
50213 /******/ ]);