OSDN Git Service

Implemeted 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         __webpack_require__(22);
66
67
68 /***/ },
69 /* 1 */
70 /***/ function(module, exports, __webpack_require__) {
71
72         __webpack_require__(2);
73         module.exports = angular;
74
75
76 /***/ },
77 /* 2 */
78 /***/ function(module, exports) {
79
80         /**
81          * @license AngularJS v1.4.8
82          * (c) 2010-2015 Google, Inc. http://angularjs.org
83          * License: MIT
84          */
85         (function(window, document, undefined) {'use strict';
86
87         /**
88          * @description
89          *
90          * This object provides a utility for producing rich Error messages within
91          * Angular. It can be called as follows:
92          *
93          * var exampleMinErr = minErr('example');
94          * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
95          *
96          * The above creates an instance of minErr in the example namespace. The
97          * resulting error will have a namespaced error code of example.one.  The
98          * resulting error will replace {0} with the value of foo, and {1} with the
99          * value of bar. The object is not restricted in the number of arguments it can
100          * take.
101          *
102          * If fewer arguments are specified than necessary for interpolation, the extra
103          * interpolation markers will be preserved in the final string.
104          *
105          * Since data will be parsed statically during a build step, some restrictions
106          * are applied with respect to how minErr instances are created and called.
107          * Instances should have names of the form namespaceMinErr for a minErr created
108          * using minErr('namespace') . Error codes, namespaces and template strings
109          * should all be static strings, not variables or general expressions.
110          *
111          * @param {string} module The namespace to use for the new minErr instance.
112          * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
113          *   error from returned function, for cases when a particular type of error is useful.
114          * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
115          */
116
117         function minErr(module, ErrorConstructor) {
118           ErrorConstructor = ErrorConstructor || Error;
119           return function() {
120             var SKIP_INDEXES = 2;
121
122             var templateArgs = arguments,
123               code = templateArgs[0],
124               message = '[' + (module ? module + ':' : '') + code + '] ',
125               template = templateArgs[1],
126               paramPrefix, i;
127
128             message += template.replace(/\{\d+\}/g, function(match) {
129               var index = +match.slice(1, -1),
130                 shiftedIndex = index + SKIP_INDEXES;
131
132               if (shiftedIndex < templateArgs.length) {
133                 return toDebugString(templateArgs[shiftedIndex]);
134               }
135
136               return match;
137             });
138
139             message += '\nhttp://errors.angularjs.org/1.4.8/' +
140               (module ? module + '/' : '') + code;
141
142             for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
143               message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
144                 encodeURIComponent(toDebugString(templateArgs[i]));
145             }
146
147             return new ErrorConstructor(message);
148           };
149         }
150
151         /* We need to tell jshint what variables are being exported */
152         /* global angular: true,
153           msie: true,
154           jqLite: true,
155           jQuery: true,
156           slice: true,
157           splice: true,
158           push: true,
159           toString: true,
160           ngMinErr: true,
161           angularModule: true,
162           uid: true,
163           REGEX_STRING_REGEXP: true,
164           VALIDITY_STATE_PROPERTY: true,
165
166           lowercase: true,
167           uppercase: true,
168           manualLowercase: true,
169           manualUppercase: true,
170           nodeName_: true,
171           isArrayLike: true,
172           forEach: true,
173           forEachSorted: true,
174           reverseParams: true,
175           nextUid: true,
176           setHashKey: true,
177           extend: true,
178           toInt: true,
179           inherit: true,
180           merge: true,
181           noop: true,
182           identity: true,
183           valueFn: true,
184           isUndefined: true,
185           isDefined: true,
186           isObject: true,
187           isBlankObject: true,
188           isString: true,
189           isNumber: true,
190           isDate: true,
191           isArray: true,
192           isFunction: true,
193           isRegExp: true,
194           isWindow: true,
195           isScope: true,
196           isFile: true,
197           isFormData: true,
198           isBlob: true,
199           isBoolean: true,
200           isPromiseLike: true,
201           trim: true,
202           escapeForRegexp: true,
203           isElement: true,
204           makeMap: true,
205           includes: true,
206           arrayRemove: true,
207           copy: true,
208           shallowCopy: true,
209           equals: true,
210           csp: true,
211           jq: true,
212           concat: true,
213           sliceArgs: true,
214           bind: true,
215           toJsonReplacer: true,
216           toJson: true,
217           fromJson: true,
218           convertTimezoneToLocal: true,
219           timezoneToOffset: true,
220           startingTag: true,
221           tryDecodeURIComponent: true,
222           parseKeyValue: true,
223           toKeyValue: true,
224           encodeUriSegment: true,
225           encodeUriQuery: true,
226           angularInit: true,
227           bootstrap: true,
228           getTestability: true,
229           snake_case: true,
230           bindJQuery: true,
231           assertArg: true,
232           assertArgFn: true,
233           assertNotHasOwnProperty: true,
234           getter: true,
235           getBlockNodes: true,
236           hasOwnProperty: true,
237           createMap: true,
238
239           NODE_TYPE_ELEMENT: true,
240           NODE_TYPE_ATTRIBUTE: true,
241           NODE_TYPE_TEXT: true,
242           NODE_TYPE_COMMENT: true,
243           NODE_TYPE_DOCUMENT: true,
244           NODE_TYPE_DOCUMENT_FRAGMENT: true,
245         */
246
247         ////////////////////////////////////
248
249         /**
250          * @ngdoc module
251          * @name ng
252          * @module ng
253          * @description
254          *
255          * # ng (core module)
256          * The ng module is loaded by default when an AngularJS application is started. The module itself
257          * contains the essential components for an AngularJS application to function. The table below
258          * lists a high level breakdown of each of the services/factories, filters, directives and testing
259          * components available within this core module.
260          *
261          * <div doc-module-components="ng"></div>
262          */
263
264         var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
265
266         // The name of a form control's ValidityState property.
267         // This is used so that it's possible for internal tests to create mock ValidityStates.
268         var VALIDITY_STATE_PROPERTY = 'validity';
269
270         /**
271          * @ngdoc function
272          * @name angular.lowercase
273          * @module ng
274          * @kind function
275          *
276          * @description Converts the specified string to lowercase.
277          * @param {string} string String to be converted to lowercase.
278          * @returns {string} Lowercased string.
279          */
280         var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
281         var hasOwnProperty = Object.prototype.hasOwnProperty;
282
283         /**
284          * @ngdoc function
285          * @name angular.uppercase
286          * @module ng
287          * @kind function
288          *
289          * @description Converts the specified string to uppercase.
290          * @param {string} string String to be converted to uppercase.
291          * @returns {string} Uppercased string.
292          */
293         var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
294
295
296         var manualLowercase = function(s) {
297           /* jshint bitwise: false */
298           return isString(s)
299               ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
300               : s;
301         };
302         var manualUppercase = function(s) {
303           /* jshint bitwise: false */
304           return isString(s)
305               ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
306               : s;
307         };
308
309
310         // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
311         // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
312         // with correct but slower alternatives.
313         if ('i' !== 'I'.toLowerCase()) {
314           lowercase = manualLowercase;
315           uppercase = manualUppercase;
316         }
317
318
319         var
320             msie,             // holds major version number for IE, or NaN if UA is not IE.
321             jqLite,           // delay binding since jQuery could be loaded after us.
322             jQuery,           // delay binding
323             slice             = [].slice,
324             splice            = [].splice,
325             push              = [].push,
326             toString          = Object.prototype.toString,
327             getPrototypeOf    = Object.getPrototypeOf,
328             ngMinErr          = minErr('ng'),
329
330             /** @name angular */
331             angular           = window.angular || (window.angular = {}),
332             angularModule,
333             uid               = 0;
334
335         /**
336          * documentMode is an IE-only property
337          * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
338          */
339         msie = document.documentMode;
340
341
342         /**
343          * @private
344          * @param {*} obj
345          * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
346          *                   String ...)
347          */
348         function isArrayLike(obj) {
349
350           // `null`, `undefined` and `window` are not array-like
351           if (obj == null || isWindow(obj)) return false;
352
353           // arrays, strings and jQuery/jqLite objects are array like
354           // * jqLite is either the jQuery or jqLite constructor function
355           // * we have to check the existance of jqLite first as this method is called
356           //   via the forEach method when constructing the jqLite object in the first place
357           if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
358
359           // Support: iOS 8.2 (not reproducible in simulator)
360           // "length" in obj used to prevent JIT error (gh-11508)
361           var length = "length" in Object(obj) && obj.length;
362
363           // NodeList objects (with `item` method) and
364           // other objects with suitable length characteristics are array-like
365           return isNumber(length) &&
366             (length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
367         }
368
369         /**
370          * @ngdoc function
371          * @name angular.forEach
372          * @module ng
373          * @kind function
374          *
375          * @description
376          * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
377          * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
378          * is the value of an object property or an array element, `key` is the object property key or
379          * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
380          *
381          * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
382          * using the `hasOwnProperty` method.
383          *
384          * Unlike ES262's
385          * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
386          * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
387          * return the value provided.
388          *
389            ```js
390              var values = {name: 'misko', gender: 'male'};
391              var log = [];
392              angular.forEach(values, function(value, key) {
393                this.push(key + ': ' + value);
394              }, log);
395              expect(log).toEqual(['name: misko', 'gender: male']);
396            ```
397          *
398          * @param {Object|Array} obj Object to iterate over.
399          * @param {Function} iterator Iterator function.
400          * @param {Object=} context Object to become context (`this`) for the iterator function.
401          * @returns {Object|Array} Reference to `obj`.
402          */
403
404         function forEach(obj, iterator, context) {
405           var key, length;
406           if (obj) {
407             if (isFunction(obj)) {
408               for (key in obj) {
409                 // Need to check if hasOwnProperty exists,
410                 // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
411                 if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
412                   iterator.call(context, obj[key], key, obj);
413                 }
414               }
415             } else if (isArray(obj) || isArrayLike(obj)) {
416               var isPrimitive = typeof obj !== 'object';
417               for (key = 0, length = obj.length; key < length; key++) {
418                 if (isPrimitive || key in obj) {
419                   iterator.call(context, obj[key], key, obj);
420                 }
421               }
422             } else if (obj.forEach && obj.forEach !== forEach) {
423                 obj.forEach(iterator, context, obj);
424             } else if (isBlankObject(obj)) {
425               // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
426               for (key in obj) {
427                 iterator.call(context, obj[key], key, obj);
428               }
429             } else if (typeof obj.hasOwnProperty === 'function') {
430               // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
431               for (key in obj) {
432                 if (obj.hasOwnProperty(key)) {
433                   iterator.call(context, obj[key], key, obj);
434                 }
435               }
436             } else {
437               // Slow path for objects which do not have a method `hasOwnProperty`
438               for (key in obj) {
439                 if (hasOwnProperty.call(obj, key)) {
440                   iterator.call(context, obj[key], key, obj);
441                 }
442               }
443             }
444           }
445           return obj;
446         }
447
448         function forEachSorted(obj, iterator, context) {
449           var keys = Object.keys(obj).sort();
450           for (var i = 0; i < keys.length; i++) {
451             iterator.call(context, obj[keys[i]], keys[i]);
452           }
453           return keys;
454         }
455
456
457         /**
458          * when using forEach the params are value, key, but it is often useful to have key, value.
459          * @param {function(string, *)} iteratorFn
460          * @returns {function(*, string)}
461          */
462         function reverseParams(iteratorFn) {
463           return function(value, key) { iteratorFn(key, value); };
464         }
465
466         /**
467          * A consistent way of creating unique IDs in angular.
468          *
469          * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
470          * we hit number precision issues in JavaScript.
471          *
472          * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
473          *
474          * @returns {number} an unique alpha-numeric string
475          */
476         function nextUid() {
477           return ++uid;
478         }
479
480
481         /**
482          * Set or clear the hashkey for an object.
483          * @param obj object
484          * @param h the hashkey (!truthy to delete the hashkey)
485          */
486         function setHashKey(obj, h) {
487           if (h) {
488             obj.$$hashKey = h;
489           } else {
490             delete obj.$$hashKey;
491           }
492         }
493
494
495         function baseExtend(dst, objs, deep) {
496           var h = dst.$$hashKey;
497
498           for (var i = 0, ii = objs.length; i < ii; ++i) {
499             var obj = objs[i];
500             if (!isObject(obj) && !isFunction(obj)) continue;
501             var keys = Object.keys(obj);
502             for (var j = 0, jj = keys.length; j < jj; j++) {
503               var key = keys[j];
504               var src = obj[key];
505
506               if (deep && isObject(src)) {
507                 if (isDate(src)) {
508                   dst[key] = new Date(src.valueOf());
509                 } else if (isRegExp(src)) {
510                   dst[key] = new RegExp(src);
511                 } else if (src.nodeName) {
512                   dst[key] = src.cloneNode(true);
513                 } else if (isElement(src)) {
514                   dst[key] = src.clone();
515                 } else {
516                   if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
517                   baseExtend(dst[key], [src], true);
518                 }
519               } else {
520                 dst[key] = src;
521               }
522             }
523           }
524
525           setHashKey(dst, h);
526           return dst;
527         }
528
529         /**
530          * @ngdoc function
531          * @name angular.extend
532          * @module ng
533          * @kind function
534          *
535          * @description
536          * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
537          * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
538          * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
539          *
540          * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
541          * {@link angular.merge} for this.
542          *
543          * @param {Object} dst Destination object.
544          * @param {...Object} src Source object(s).
545          * @returns {Object} Reference to `dst`.
546          */
547         function extend(dst) {
548           return baseExtend(dst, slice.call(arguments, 1), false);
549         }
550
551
552         /**
553         * @ngdoc function
554         * @name angular.merge
555         * @module ng
556         * @kind function
557         *
558         * @description
559         * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
560         * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
561         * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
562         *
563         * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
564         * objects, performing a deep copy.
565         *
566         * @param {Object} dst Destination object.
567         * @param {...Object} src Source object(s).
568         * @returns {Object} Reference to `dst`.
569         */
570         function merge(dst) {
571           return baseExtend(dst, slice.call(arguments, 1), true);
572         }
573
574
575
576         function toInt(str) {
577           return parseInt(str, 10);
578         }
579
580
581         function inherit(parent, extra) {
582           return extend(Object.create(parent), extra);
583         }
584
585         /**
586          * @ngdoc function
587          * @name angular.noop
588          * @module ng
589          * @kind function
590          *
591          * @description
592          * A function that performs no operations. This function can be useful when writing code in the
593          * functional style.
594            ```js
595              function foo(callback) {
596                var result = calculateResult();
597                (callback || angular.noop)(result);
598              }
599            ```
600          */
601         function noop() {}
602         noop.$inject = [];
603
604
605         /**
606          * @ngdoc function
607          * @name angular.identity
608          * @module ng
609          * @kind function
610          *
611          * @description
612          * A function that returns its first argument. This function is useful when writing code in the
613          * functional style.
614          *
615            ```js
616              function transformer(transformationFn, value) {
617                return (transformationFn || angular.identity)(value);
618              };
619            ```
620           * @param {*} value to be returned.
621           * @returns {*} the value passed in.
622          */
623         function identity($) {return $;}
624         identity.$inject = [];
625
626
627         function valueFn(value) {return function() {return value;};}
628
629         function hasCustomToString(obj) {
630           return isFunction(obj.toString) && obj.toString !== toString;
631         }
632
633
634         /**
635          * @ngdoc function
636          * @name angular.isUndefined
637          * @module ng
638          * @kind function
639          *
640          * @description
641          * Determines if a reference is undefined.
642          *
643          * @param {*} value Reference to check.
644          * @returns {boolean} True if `value` is undefined.
645          */
646         function isUndefined(value) {return typeof value === 'undefined';}
647
648
649         /**
650          * @ngdoc function
651          * @name angular.isDefined
652          * @module ng
653          * @kind function
654          *
655          * @description
656          * Determines if a reference is defined.
657          *
658          * @param {*} value Reference to check.
659          * @returns {boolean} True if `value` is defined.
660          */
661         function isDefined(value) {return typeof value !== 'undefined';}
662
663
664         /**
665          * @ngdoc function
666          * @name angular.isObject
667          * @module ng
668          * @kind function
669          *
670          * @description
671          * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
672          * considered to be objects. Note that JavaScript arrays are objects.
673          *
674          * @param {*} value Reference to check.
675          * @returns {boolean} True if `value` is an `Object` but not `null`.
676          */
677         function isObject(value) {
678           // http://jsperf.com/isobject4
679           return value !== null && typeof value === 'object';
680         }
681
682
683         /**
684          * Determine if a value is an object with a null prototype
685          *
686          * @returns {boolean} True if `value` is an `Object` with a null prototype
687          */
688         function isBlankObject(value) {
689           return value !== null && typeof value === 'object' && !getPrototypeOf(value);
690         }
691
692
693         /**
694          * @ngdoc function
695          * @name angular.isString
696          * @module ng
697          * @kind function
698          *
699          * @description
700          * Determines if a reference is a `String`.
701          *
702          * @param {*} value Reference to check.
703          * @returns {boolean} True if `value` is a `String`.
704          */
705         function isString(value) {return typeof value === 'string';}
706
707
708         /**
709          * @ngdoc function
710          * @name angular.isNumber
711          * @module ng
712          * @kind function
713          *
714          * @description
715          * Determines if a reference is a `Number`.
716          *
717          * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
718          *
719          * If you wish to exclude these then you can use the native
720          * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
721          * method.
722          *
723          * @param {*} value Reference to check.
724          * @returns {boolean} True if `value` is a `Number`.
725          */
726         function isNumber(value) {return typeof value === 'number';}
727
728
729         /**
730          * @ngdoc function
731          * @name angular.isDate
732          * @module ng
733          * @kind function
734          *
735          * @description
736          * Determines if a value is a date.
737          *
738          * @param {*} value Reference to check.
739          * @returns {boolean} True if `value` is a `Date`.
740          */
741         function isDate(value) {
742           return toString.call(value) === '[object Date]';
743         }
744
745
746         /**
747          * @ngdoc function
748          * @name angular.isArray
749          * @module ng
750          * @kind function
751          *
752          * @description
753          * Determines if a reference is an `Array`.
754          *
755          * @param {*} value Reference to check.
756          * @returns {boolean} True if `value` is an `Array`.
757          */
758         var isArray = Array.isArray;
759
760         /**
761          * @ngdoc function
762          * @name angular.isFunction
763          * @module ng
764          * @kind function
765          *
766          * @description
767          * Determines if a reference is a `Function`.
768          *
769          * @param {*} value Reference to check.
770          * @returns {boolean} True if `value` is a `Function`.
771          */
772         function isFunction(value) {return typeof value === 'function';}
773
774
775         /**
776          * Determines if a value is a regular expression object.
777          *
778          * @private
779          * @param {*} value Reference to check.
780          * @returns {boolean} True if `value` is a `RegExp`.
781          */
782         function isRegExp(value) {
783           return toString.call(value) === '[object RegExp]';
784         }
785
786
787         /**
788          * Checks if `obj` is a window object.
789          *
790          * @private
791          * @param {*} obj Object to check
792          * @returns {boolean} True if `obj` is a window obj.
793          */
794         function isWindow(obj) {
795           return obj && obj.window === obj;
796         }
797
798
799         function isScope(obj) {
800           return obj && obj.$evalAsync && obj.$watch;
801         }
802
803
804         function isFile(obj) {
805           return toString.call(obj) === '[object File]';
806         }
807
808
809         function isFormData(obj) {
810           return toString.call(obj) === '[object FormData]';
811         }
812
813
814         function isBlob(obj) {
815           return toString.call(obj) === '[object Blob]';
816         }
817
818
819         function isBoolean(value) {
820           return typeof value === 'boolean';
821         }
822
823
824         function isPromiseLike(obj) {
825           return obj && isFunction(obj.then);
826         }
827
828
829         var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
830         function isTypedArray(value) {
831           return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
832         }
833
834
835         var trim = function(value) {
836           return isString(value) ? value.trim() : value;
837         };
838
839         // Copied from:
840         // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
841         // Prereq: s is a string.
842         var escapeForRegexp = function(s) {
843           return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
844                    replace(/\x08/g, '\\x08');
845         };
846
847
848         /**
849          * @ngdoc function
850          * @name angular.isElement
851          * @module ng
852          * @kind function
853          *
854          * @description
855          * Determines if a reference is a DOM element (or wrapped jQuery element).
856          *
857          * @param {*} value Reference to check.
858          * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
859          */
860         function isElement(node) {
861           return !!(node &&
862             (node.nodeName  // we are a direct element
863             || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
864         }
865
866         /**
867          * @param str 'key1,key2,...'
868          * @returns {object} in the form of {key1:true, key2:true, ...}
869          */
870         function makeMap(str) {
871           var obj = {}, items = str.split(","), i;
872           for (i = 0; i < items.length; i++) {
873             obj[items[i]] = true;
874           }
875           return obj;
876         }
877
878
879         function nodeName_(element) {
880           return lowercase(element.nodeName || (element[0] && element[0].nodeName));
881         }
882
883         function includes(array, obj) {
884           return Array.prototype.indexOf.call(array, obj) != -1;
885         }
886
887         function arrayRemove(array, value) {
888           var index = array.indexOf(value);
889           if (index >= 0) {
890             array.splice(index, 1);
891           }
892           return index;
893         }
894
895         /**
896          * @ngdoc function
897          * @name angular.copy
898          * @module ng
899          * @kind function
900          *
901          * @description
902          * Creates a deep copy of `source`, which should be an object or an array.
903          *
904          * * If no destination is supplied, a copy of the object or array is created.
905          * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
906          *   are deleted and then all elements/properties from the source are copied to it.
907          * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
908          * * If `source` is identical to 'destination' an exception will be thrown.
909          *
910          * @param {*} source The source that will be used to make a copy.
911          *                   Can be any type, including primitives, `null`, and `undefined`.
912          * @param {(Object|Array)=} destination Destination into which the source is copied. If
913          *     provided, must be of the same type as `source`.
914          * @returns {*} The copy or updated `destination`, if `destination` was specified.
915          *
916          * @example
917          <example module="copyExample">
918          <file name="index.html">
919          <div ng-controller="ExampleController">
920          <form novalidate class="simple-form">
921          Name: <input type="text" ng-model="user.name" /><br />
922          E-mail: <input type="email" ng-model="user.email" /><br />
923          Gender: <input type="radio" ng-model="user.gender" value="male" />male
924          <input type="radio" ng-model="user.gender" value="female" />female<br />
925          <button ng-click="reset()">RESET</button>
926          <button ng-click="update(user)">SAVE</button>
927          </form>
928          <pre>form = {{user | json}}</pre>
929          <pre>master = {{master | json}}</pre>
930          </div>
931
932          <script>
933           angular.module('copyExample', [])
934             .controller('ExampleController', ['$scope', function($scope) {
935               $scope.master= {};
936
937               $scope.update = function(user) {
938                 // Example with 1 argument
939                 $scope.master= angular.copy(user);
940               };
941
942               $scope.reset = function() {
943                 // Example with 2 arguments
944                 angular.copy($scope.master, $scope.user);
945               };
946
947               $scope.reset();
948             }]);
949          </script>
950          </file>
951          </example>
952          */
953         function copy(source, destination) {
954           var stackSource = [];
955           var stackDest = [];
956
957           if (destination) {
958             if (isTypedArray(destination)) {
959               throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
960             }
961             if (source === destination) {
962               throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
963             }
964
965             // Empty the destination object
966             if (isArray(destination)) {
967               destination.length = 0;
968             } else {
969               forEach(destination, function(value, key) {
970                 if (key !== '$$hashKey') {
971                   delete destination[key];
972                 }
973               });
974             }
975
976             stackSource.push(source);
977             stackDest.push(destination);
978             return copyRecurse(source, destination);
979           }
980
981           return copyElement(source);
982
983           function copyRecurse(source, destination) {
984             var h = destination.$$hashKey;
985             var result, key;
986             if (isArray(source)) {
987               for (var i = 0, ii = source.length; i < ii; i++) {
988                 destination.push(copyElement(source[i]));
989               }
990             } else if (isBlankObject(source)) {
991               // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
992               for (key in source) {
993                 destination[key] = copyElement(source[key]);
994               }
995             } else if (source && typeof source.hasOwnProperty === 'function') {
996               // Slow path, which must rely on hasOwnProperty
997               for (key in source) {
998                 if (source.hasOwnProperty(key)) {
999                   destination[key] = copyElement(source[key]);
1000                 }
1001               }
1002             } else {
1003               // Slowest path --- hasOwnProperty can't be called as a method
1004               for (key in source) {
1005                 if (hasOwnProperty.call(source, key)) {
1006                   destination[key] = copyElement(source[key]);
1007                 }
1008               }
1009             }
1010             setHashKey(destination, h);
1011             return destination;
1012           }
1013
1014           function copyElement(source) {
1015             // Simple values
1016             if (!isObject(source)) {
1017               return source;
1018             }
1019
1020             // Already copied values
1021             var index = stackSource.indexOf(source);
1022             if (index !== -1) {
1023               return stackDest[index];
1024             }
1025
1026             if (isWindow(source) || isScope(source)) {
1027               throw ngMinErr('cpws',
1028                 "Can't copy! Making copies of Window or Scope instances is not supported.");
1029             }
1030
1031             var needsRecurse = false;
1032             var destination;
1033
1034             if (isArray(source)) {
1035               destination = [];
1036               needsRecurse = true;
1037             } else if (isTypedArray(source)) {
1038               destination = new source.constructor(source);
1039             } else if (isDate(source)) {
1040               destination = new Date(source.getTime());
1041             } else if (isRegExp(source)) {
1042               destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
1043               destination.lastIndex = source.lastIndex;
1044             } else if (isFunction(source.cloneNode)) {
1045                 destination = source.cloneNode(true);
1046             } else {
1047               destination = Object.create(getPrototypeOf(source));
1048               needsRecurse = true;
1049             }
1050
1051             stackSource.push(source);
1052             stackDest.push(destination);
1053
1054             return needsRecurse
1055               ? copyRecurse(source, destination)
1056               : destination;
1057           }
1058         }
1059
1060         /**
1061          * Creates a shallow copy of an object, an array or a primitive.
1062          *
1063          * Assumes that there are no proto properties for objects.
1064          */
1065         function shallowCopy(src, dst) {
1066           if (isArray(src)) {
1067             dst = dst || [];
1068
1069             for (var i = 0, ii = src.length; i < ii; i++) {
1070               dst[i] = src[i];
1071             }
1072           } else if (isObject(src)) {
1073             dst = dst || {};
1074
1075             for (var key in src) {
1076               if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
1077                 dst[key] = src[key];
1078               }
1079             }
1080           }
1081
1082           return dst || src;
1083         }
1084
1085
1086         /**
1087          * @ngdoc function
1088          * @name angular.equals
1089          * @module ng
1090          * @kind function
1091          *
1092          * @description
1093          * Determines if two objects or two values are equivalent. Supports value types, regular
1094          * expressions, arrays and objects.
1095          *
1096          * Two objects or values are considered equivalent if at least one of the following is true:
1097          *
1098          * * Both objects or values pass `===` comparison.
1099          * * Both objects or values are of the same type and all of their properties are equal by
1100          *   comparing them with `angular.equals`.
1101          * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
1102          * * Both values represent the same regular expression (In JavaScript,
1103          *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
1104          *   representation matches).
1105          *
1106          * During a property comparison, properties of `function` type and properties with names
1107          * that begin with `$` are ignored.
1108          *
1109          * Scope and DOMWindow objects are being compared only by identify (`===`).
1110          *
1111          * @param {*} o1 Object or value to compare.
1112          * @param {*} o2 Object or value to compare.
1113          * @returns {boolean} True if arguments are equal.
1114          */
1115         function equals(o1, o2) {
1116           if (o1 === o2) return true;
1117           if (o1 === null || o2 === null) return false;
1118           if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1119           var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1120           if (t1 == t2) {
1121             if (t1 == 'object') {
1122               if (isArray(o1)) {
1123                 if (!isArray(o2)) return false;
1124                 if ((length = o1.length) == o2.length) {
1125                   for (key = 0; key < length; key++) {
1126                     if (!equals(o1[key], o2[key])) return false;
1127                   }
1128                   return true;
1129                 }
1130               } else if (isDate(o1)) {
1131                 if (!isDate(o2)) return false;
1132                 return equals(o1.getTime(), o2.getTime());
1133               } else if (isRegExp(o1)) {
1134                 return isRegExp(o2) ? o1.toString() == o2.toString() : false;
1135               } else {
1136                 if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1137                   isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1138                 keySet = createMap();
1139                 for (key in o1) {
1140                   if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1141                   if (!equals(o1[key], o2[key])) return false;
1142                   keySet[key] = true;
1143                 }
1144                 for (key in o2) {
1145                   if (!(key in keySet) &&
1146                       key.charAt(0) !== '$' &&
1147                       isDefined(o2[key]) &&
1148                       !isFunction(o2[key])) return false;
1149                 }
1150                 return true;
1151               }
1152             }
1153           }
1154           return false;
1155         }
1156
1157         var csp = function() {
1158           if (!isDefined(csp.rules)) {
1159
1160
1161             var ngCspElement = (document.querySelector('[ng-csp]') ||
1162                             document.querySelector('[data-ng-csp]'));
1163
1164             if (ngCspElement) {
1165               var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
1166                             ngCspElement.getAttribute('data-ng-csp');
1167               csp.rules = {
1168                 noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
1169                 noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
1170               };
1171             } else {
1172               csp.rules = {
1173                 noUnsafeEval: noUnsafeEval(),
1174                 noInlineStyle: false
1175               };
1176             }
1177           }
1178
1179           return csp.rules;
1180
1181           function noUnsafeEval() {
1182             try {
1183               /* jshint -W031, -W054 */
1184               new Function('');
1185               /* jshint +W031, +W054 */
1186               return false;
1187             } catch (e) {
1188               return true;
1189             }
1190           }
1191         };
1192
1193         /**
1194          * @ngdoc directive
1195          * @module ng
1196          * @name ngJq
1197          *
1198          * @element ANY
1199          * @param {string=} ngJq the name of the library available under `window`
1200          * to be used for angular.element
1201          * @description
1202          * Use this directive to force the angular.element library.  This should be
1203          * used to force either jqLite by leaving ng-jq blank or setting the name of
1204          * the jquery variable under window (eg. jQuery).
1205          *
1206          * Since angular looks for this directive when it is loaded (doesn't wait for the
1207          * DOMContentLoaded event), it must be placed on an element that comes before the script
1208          * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1209          * others ignored.
1210          *
1211          * @example
1212          * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1213          ```html
1214          <!doctype html>
1215          <html ng-app ng-jq>
1216          ...
1217          ...
1218          </html>
1219          ```
1220          * @example
1221          * This example shows how to use a jQuery based library of a different name.
1222          * The library name must be available at the top most 'window'.
1223          ```html
1224          <!doctype html>
1225          <html ng-app ng-jq="jQueryLib">
1226          ...
1227          ...
1228          </html>
1229          ```
1230          */
1231         var jq = function() {
1232           if (isDefined(jq.name_)) return jq.name_;
1233           var el;
1234           var i, ii = ngAttrPrefixes.length, prefix, name;
1235           for (i = 0; i < ii; ++i) {
1236             prefix = ngAttrPrefixes[i];
1237             if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1238               name = el.getAttribute(prefix + 'jq');
1239               break;
1240             }
1241           }
1242
1243           return (jq.name_ = name);
1244         };
1245
1246         function concat(array1, array2, index) {
1247           return array1.concat(slice.call(array2, index));
1248         }
1249
1250         function sliceArgs(args, startIndex) {
1251           return slice.call(args, startIndex || 0);
1252         }
1253
1254
1255         /* jshint -W101 */
1256         /**
1257          * @ngdoc function
1258          * @name angular.bind
1259          * @module ng
1260          * @kind function
1261          *
1262          * @description
1263          * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1264          * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1265          * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1266          * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1267          *
1268          * @param {Object} self Context which `fn` should be evaluated in.
1269          * @param {function()} fn Function to be bound.
1270          * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1271          * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1272          */
1273         /* jshint +W101 */
1274         function bind(self, fn) {
1275           var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1276           if (isFunction(fn) && !(fn instanceof RegExp)) {
1277             return curryArgs.length
1278               ? function() {
1279                   return arguments.length
1280                     ? fn.apply(self, concat(curryArgs, arguments, 0))
1281                     : fn.apply(self, curryArgs);
1282                 }
1283               : function() {
1284                   return arguments.length
1285                     ? fn.apply(self, arguments)
1286                     : fn.call(self);
1287                 };
1288           } else {
1289             // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1290             return fn;
1291           }
1292         }
1293
1294
1295         function toJsonReplacer(key, value) {
1296           var val = value;
1297
1298           if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1299             val = undefined;
1300           } else if (isWindow(value)) {
1301             val = '$WINDOW';
1302           } else if (value &&  document === value) {
1303             val = '$DOCUMENT';
1304           } else if (isScope(value)) {
1305             val = '$SCOPE';
1306           }
1307
1308           return val;
1309         }
1310
1311
1312         /**
1313          * @ngdoc function
1314          * @name angular.toJson
1315          * @module ng
1316          * @kind function
1317          *
1318          * @description
1319          * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1320          * stripped since angular uses this notation internally.
1321          *
1322          * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1323          * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1324          *    If set to an integer, the JSON output will contain that many spaces per indentation.
1325          * @returns {string|undefined} JSON-ified string representing `obj`.
1326          */
1327         function toJson(obj, pretty) {
1328           if (typeof obj === 'undefined') return undefined;
1329           if (!isNumber(pretty)) {
1330             pretty = pretty ? 2 : null;
1331           }
1332           return JSON.stringify(obj, toJsonReplacer, pretty);
1333         }
1334
1335
1336         /**
1337          * @ngdoc function
1338          * @name angular.fromJson
1339          * @module ng
1340          * @kind function
1341          *
1342          * @description
1343          * Deserializes a JSON string.
1344          *
1345          * @param {string} json JSON string to deserialize.
1346          * @returns {Object|Array|string|number} Deserialized JSON string.
1347          */
1348         function fromJson(json) {
1349           return isString(json)
1350               ? JSON.parse(json)
1351               : json;
1352         }
1353
1354
1355         function timezoneToOffset(timezone, fallback) {
1356           var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1357           return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1358         }
1359
1360
1361         function addDateMinutes(date, minutes) {
1362           date = new Date(date.getTime());
1363           date.setMinutes(date.getMinutes() + minutes);
1364           return date;
1365         }
1366
1367
1368         function convertTimezoneToLocal(date, timezone, reverse) {
1369           reverse = reverse ? -1 : 1;
1370           var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
1371           return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
1372         }
1373
1374
1375         /**
1376          * @returns {string} Returns the string representation of the element.
1377          */
1378         function startingTag(element) {
1379           element = jqLite(element).clone();
1380           try {
1381             // turns out IE does not let you set .html() on elements which
1382             // are not allowed to have children. So we just ignore it.
1383             element.empty();
1384           } catch (e) {}
1385           var elemHtml = jqLite('<div>').append(element).html();
1386           try {
1387             return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1388                 elemHtml.
1389                   match(/^(<[^>]+>)/)[1].
1390                   replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1391           } catch (e) {
1392             return lowercase(elemHtml);
1393           }
1394
1395         }
1396
1397
1398         /////////////////////////////////////////////////
1399
1400         /**
1401          * Tries to decode the URI component without throwing an exception.
1402          *
1403          * @private
1404          * @param str value potential URI component to check.
1405          * @returns {boolean} True if `value` can be decoded
1406          * with the decodeURIComponent function.
1407          */
1408         function tryDecodeURIComponent(value) {
1409           try {
1410             return decodeURIComponent(value);
1411           } catch (e) {
1412             // Ignore any invalid uri component
1413           }
1414         }
1415
1416
1417         /**
1418          * Parses an escaped url query string into key-value pairs.
1419          * @returns {Object.<string,boolean|Array>}
1420          */
1421         function parseKeyValue(/**string*/keyValue) {
1422           var obj = {};
1423           forEach((keyValue || "").split('&'), function(keyValue) {
1424             var splitPoint, key, val;
1425             if (keyValue) {
1426               key = keyValue = keyValue.replace(/\+/g,'%20');
1427               splitPoint = keyValue.indexOf('=');
1428               if (splitPoint !== -1) {
1429                 key = keyValue.substring(0, splitPoint);
1430                 val = keyValue.substring(splitPoint + 1);
1431               }
1432               key = tryDecodeURIComponent(key);
1433               if (isDefined(key)) {
1434                 val = isDefined(val) ? tryDecodeURIComponent(val) : true;
1435                 if (!hasOwnProperty.call(obj, key)) {
1436                   obj[key] = val;
1437                 } else if (isArray(obj[key])) {
1438                   obj[key].push(val);
1439                 } else {
1440                   obj[key] = [obj[key],val];
1441                 }
1442               }
1443             }
1444           });
1445           return obj;
1446         }
1447
1448         function toKeyValue(obj) {
1449           var parts = [];
1450           forEach(obj, function(value, key) {
1451             if (isArray(value)) {
1452               forEach(value, function(arrayValue) {
1453                 parts.push(encodeUriQuery(key, true) +
1454                            (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1455               });
1456             } else {
1457             parts.push(encodeUriQuery(key, true) +
1458                        (value === true ? '' : '=' + encodeUriQuery(value, true)));
1459             }
1460           });
1461           return parts.length ? parts.join('&') : '';
1462         }
1463
1464
1465         /**
1466          * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1467          * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1468          * segments:
1469          *    segment       = *pchar
1470          *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1471          *    pct-encoded   = "%" HEXDIG HEXDIG
1472          *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1473          *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1474          *                     / "*" / "+" / "," / ";" / "="
1475          */
1476         function encodeUriSegment(val) {
1477           return encodeUriQuery(val, true).
1478                      replace(/%26/gi, '&').
1479                      replace(/%3D/gi, '=').
1480                      replace(/%2B/gi, '+');
1481         }
1482
1483
1484         /**
1485          * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1486          * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1487          * encoded per http://tools.ietf.org/html/rfc3986:
1488          *    query       = *( pchar / "/" / "?" )
1489          *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1490          *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1491          *    pct-encoded   = "%" HEXDIG HEXDIG
1492          *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1493          *                     / "*" / "+" / "," / ";" / "="
1494          */
1495         function encodeUriQuery(val, pctEncodeSpaces) {
1496           return encodeURIComponent(val).
1497                      replace(/%40/gi, '@').
1498                      replace(/%3A/gi, ':').
1499                      replace(/%24/g, '$').
1500                      replace(/%2C/gi, ',').
1501                      replace(/%3B/gi, ';').
1502                      replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1503         }
1504
1505         var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1506
1507         function getNgAttribute(element, ngAttr) {
1508           var attr, i, ii = ngAttrPrefixes.length;
1509           for (i = 0; i < ii; ++i) {
1510             attr = ngAttrPrefixes[i] + ngAttr;
1511             if (isString(attr = element.getAttribute(attr))) {
1512               return attr;
1513             }
1514           }
1515           return null;
1516         }
1517
1518         /**
1519          * @ngdoc directive
1520          * @name ngApp
1521          * @module ng
1522          *
1523          * @element ANY
1524          * @param {angular.Module} ngApp an optional application
1525          *   {@link angular.module module} name to load.
1526          * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1527          *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1528          *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1529          *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1530          *   tracking down the root of these bugs.
1531          *
1532          * @description
1533          *
1534          * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1535          * designates the **root element** of the application and is typically placed near the root element
1536          * of the page - e.g. on the `<body>` or `<html>` tags.
1537          *
1538          * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1539          * found in the document will be used to define the root element to auto-bootstrap as an
1540          * application. To run multiple applications in an HTML document you must manually bootstrap them using
1541          * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1542          *
1543          * You can specify an **AngularJS module** to be used as the root module for the application.  This
1544          * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1545          * should contain the application code needed or have dependencies on other modules that will
1546          * contain the code. See {@link angular.module} for more information.
1547          *
1548          * In the example below if the `ngApp` directive were not placed on the `html` element then the
1549          * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1550          * would not be resolved to `3`.
1551          *
1552          * `ngApp` is the easiest, and most common way to bootstrap an application.
1553          *
1554          <example module="ngAppDemo">
1555            <file name="index.html">
1556            <div ng-controller="ngAppDemoController">
1557              I can add: {{a}} + {{b}} =  {{ a+b }}
1558            </div>
1559            </file>
1560            <file name="script.js">
1561            angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1562              $scope.a = 1;
1563              $scope.b = 2;
1564            });
1565            </file>
1566          </example>
1567          *
1568          * Using `ngStrictDi`, you would see something like this:
1569          *
1570          <example ng-app-included="true">
1571            <file name="index.html">
1572            <div ng-app="ngAppStrictDemo" ng-strict-di>
1573                <div ng-controller="GoodController1">
1574                    I can add: {{a}} + {{b}} =  {{ a+b }}
1575
1576                    <p>This renders because the controller does not fail to
1577                       instantiate, by using explicit annotation style (see
1578                       script.js for details)
1579                    </p>
1580                </div>
1581
1582                <div ng-controller="GoodController2">
1583                    Name: <input ng-model="name"><br />
1584                    Hello, {{name}}!
1585
1586                    <p>This renders because the controller does not fail to
1587                       instantiate, by using explicit annotation style
1588                       (see script.js for details)
1589                    </p>
1590                </div>
1591
1592                <div ng-controller="BadController">
1593                    I can add: {{a}} + {{b}} =  {{ a+b }}
1594
1595                    <p>The controller could not be instantiated, due to relying
1596                       on automatic function annotations (which are disabled in
1597                       strict mode). As such, the content of this section is not
1598                       interpolated, and there should be an error in your web console.
1599                    </p>
1600                </div>
1601            </div>
1602            </file>
1603            <file name="script.js">
1604            angular.module('ngAppStrictDemo', [])
1605              // BadController will fail to instantiate, due to relying on automatic function annotation,
1606              // rather than an explicit annotation
1607              .controller('BadController', function($scope) {
1608                $scope.a = 1;
1609                $scope.b = 2;
1610              })
1611              // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1612              // due to using explicit annotations using the array style and $inject property, respectively.
1613              .controller('GoodController1', ['$scope', function($scope) {
1614                $scope.a = 1;
1615                $scope.b = 2;
1616              }])
1617              .controller('GoodController2', GoodController2);
1618              function GoodController2($scope) {
1619                $scope.name = "World";
1620              }
1621              GoodController2.$inject = ['$scope'];
1622            </file>
1623            <file name="style.css">
1624            div[ng-controller] {
1625                margin-bottom: 1em;
1626                -webkit-border-radius: 4px;
1627                border-radius: 4px;
1628                border: 1px solid;
1629                padding: .5em;
1630            }
1631            div[ng-controller^=Good] {
1632                border-color: #d6e9c6;
1633                background-color: #dff0d8;
1634                color: #3c763d;
1635            }
1636            div[ng-controller^=Bad] {
1637                border-color: #ebccd1;
1638                background-color: #f2dede;
1639                color: #a94442;
1640                margin-bottom: 0;
1641            }
1642            </file>
1643          </example>
1644          */
1645         function angularInit(element, bootstrap) {
1646           var appElement,
1647               module,
1648               config = {};
1649
1650           // The element `element` has priority over any other element
1651           forEach(ngAttrPrefixes, function(prefix) {
1652             var name = prefix + 'app';
1653
1654             if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1655               appElement = element;
1656               module = element.getAttribute(name);
1657             }
1658           });
1659           forEach(ngAttrPrefixes, function(prefix) {
1660             var name = prefix + 'app';
1661             var candidate;
1662
1663             if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1664               appElement = candidate;
1665               module = candidate.getAttribute(name);
1666             }
1667           });
1668           if (appElement) {
1669             config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1670             bootstrap(appElement, module ? [module] : [], config);
1671           }
1672         }
1673
1674         /**
1675          * @ngdoc function
1676          * @name angular.bootstrap
1677          * @module ng
1678          * @description
1679          * Use this function to manually start up angular application.
1680          *
1681          * See: {@link guide/bootstrap Bootstrap}
1682          *
1683          * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1684          * They must use {@link ng.directive:ngApp ngApp}.
1685          *
1686          * Angular will detect if it has been loaded into the browser more than once and only allow the
1687          * first loaded script to be bootstrapped and will report a warning to the browser console for
1688          * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1689          * multiple instances of Angular try to work on the DOM.
1690          *
1691          * ```html
1692          * <!doctype html>
1693          * <html>
1694          * <body>
1695          * <div ng-controller="WelcomeController">
1696          *   {{greeting}}
1697          * </div>
1698          *
1699          * <script src="angular.js"></script>
1700          * <script>
1701          *   var app = angular.module('demo', [])
1702          *   .controller('WelcomeController', function($scope) {
1703          *       $scope.greeting = 'Welcome!';
1704          *   });
1705          *   angular.bootstrap(document, ['demo']);
1706          * </script>
1707          * </body>
1708          * </html>
1709          * ```
1710          *
1711          * @param {DOMElement} element DOM element which is the root of angular application.
1712          * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1713          *     Each item in the array should be the name of a predefined module or a (DI annotated)
1714          *     function that will be invoked by the injector as a `config` block.
1715          *     See: {@link angular.module modules}
1716          * @param {Object=} config an object for defining configuration options for the application. The
1717          *     following keys are supported:
1718          *
1719          * * `strictDi` - disable automatic function annotation for the application. This is meant to
1720          *   assist in finding bugs which break minified code. Defaults to `false`.
1721          *
1722          * @returns {auto.$injector} Returns the newly created injector for this app.
1723          */
1724         function bootstrap(element, modules, config) {
1725           if (!isObject(config)) config = {};
1726           var defaultConfig = {
1727             strictDi: false
1728           };
1729           config = extend(defaultConfig, config);
1730           var doBootstrap = function() {
1731             element = jqLite(element);
1732
1733             if (element.injector()) {
1734               var tag = (element[0] === document) ? 'document' : startingTag(element);
1735               //Encode angle brackets to prevent input from being sanitized to empty string #8683
1736               throw ngMinErr(
1737                   'btstrpd',
1738                   "App Already Bootstrapped with this Element '{0}'",
1739                   tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1740             }
1741
1742             modules = modules || [];
1743             modules.unshift(['$provide', function($provide) {
1744               $provide.value('$rootElement', element);
1745             }]);
1746
1747             if (config.debugInfoEnabled) {
1748               // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1749               modules.push(['$compileProvider', function($compileProvider) {
1750                 $compileProvider.debugInfoEnabled(true);
1751               }]);
1752             }
1753
1754             modules.unshift('ng');
1755             var injector = createInjector(modules, config.strictDi);
1756             injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1757                function bootstrapApply(scope, element, compile, injector) {
1758                 scope.$apply(function() {
1759                   element.data('$injector', injector);
1760                   compile(element)(scope);
1761                 });
1762               }]
1763             );
1764             return injector;
1765           };
1766
1767           var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1768           var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1769
1770           if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1771             config.debugInfoEnabled = true;
1772             window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1773           }
1774
1775           if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1776             return doBootstrap();
1777           }
1778
1779           window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1780           angular.resumeBootstrap = function(extraModules) {
1781             forEach(extraModules, function(module) {
1782               modules.push(module);
1783             });
1784             return doBootstrap();
1785           };
1786
1787           if (isFunction(angular.resumeDeferredBootstrap)) {
1788             angular.resumeDeferredBootstrap();
1789           }
1790         }
1791
1792         /**
1793          * @ngdoc function
1794          * @name angular.reloadWithDebugInfo
1795          * @module ng
1796          * @description
1797          * Use this function to reload the current application with debug information turned on.
1798          * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1799          *
1800          * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1801          */
1802         function reloadWithDebugInfo() {
1803           window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1804           window.location.reload();
1805         }
1806
1807         /**
1808          * @name angular.getTestability
1809          * @module ng
1810          * @description
1811          * Get the testability service for the instance of Angular on the given
1812          * element.
1813          * @param {DOMElement} element DOM element which is the root of angular application.
1814          */
1815         function getTestability(rootElement) {
1816           var injector = angular.element(rootElement).injector();
1817           if (!injector) {
1818             throw ngMinErr('test',
1819               'no injector found for element argument to getTestability');
1820           }
1821           return injector.get('$$testability');
1822         }
1823
1824         var SNAKE_CASE_REGEXP = /[A-Z]/g;
1825         function snake_case(name, separator) {
1826           separator = separator || '_';
1827           return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1828             return (pos ? separator : '') + letter.toLowerCase();
1829           });
1830         }
1831
1832         var bindJQueryFired = false;
1833         var skipDestroyOnNextJQueryCleanData;
1834         function bindJQuery() {
1835           var originalCleanData;
1836
1837           if (bindJQueryFired) {
1838             return;
1839           }
1840
1841           // bind to jQuery if present;
1842           var jqName = jq();
1843           jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
1844                    !jqName             ? undefined     :   // use jqLite
1845                                          window[jqName];   // use jQuery specified by `ngJq`
1846
1847           // Use jQuery if it exists with proper functionality, otherwise default to us.
1848           // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1849           // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1850           // versions. It will not work for sure with jQuery <1.7, though.
1851           if (jQuery && jQuery.fn.on) {
1852             jqLite = jQuery;
1853             extend(jQuery.fn, {
1854               scope: JQLitePrototype.scope,
1855               isolateScope: JQLitePrototype.isolateScope,
1856               controller: JQLitePrototype.controller,
1857               injector: JQLitePrototype.injector,
1858               inheritedData: JQLitePrototype.inheritedData
1859             });
1860
1861             // All nodes removed from the DOM via various jQuery APIs like .remove()
1862             // are passed through jQuery.cleanData. Monkey-patch this method to fire
1863             // the $destroy event on all removed nodes.
1864             originalCleanData = jQuery.cleanData;
1865             jQuery.cleanData = function(elems) {
1866               var events;
1867               if (!skipDestroyOnNextJQueryCleanData) {
1868                 for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1869                   events = jQuery._data(elem, "events");
1870                   if (events && events.$destroy) {
1871                     jQuery(elem).triggerHandler('$destroy');
1872                   }
1873                 }
1874               } else {
1875                 skipDestroyOnNextJQueryCleanData = false;
1876               }
1877               originalCleanData(elems);
1878             };
1879           } else {
1880             jqLite = JQLite;
1881           }
1882
1883           angular.element = jqLite;
1884
1885           // Prevent double-proxying.
1886           bindJQueryFired = true;
1887         }
1888
1889         /**
1890          * throw error if the argument is falsy.
1891          */
1892         function assertArg(arg, name, reason) {
1893           if (!arg) {
1894             throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1895           }
1896           return arg;
1897         }
1898
1899         function assertArgFn(arg, name, acceptArrayAnnotation) {
1900           if (acceptArrayAnnotation && isArray(arg)) {
1901               arg = arg[arg.length - 1];
1902           }
1903
1904           assertArg(isFunction(arg), name, 'not a function, got ' +
1905               (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1906           return arg;
1907         }
1908
1909         /**
1910          * throw error if the name given is hasOwnProperty
1911          * @param  {String} name    the name to test
1912          * @param  {String} context the context in which the name is used, such as module or directive
1913          */
1914         function assertNotHasOwnProperty(name, context) {
1915           if (name === 'hasOwnProperty') {
1916             throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1917           }
1918         }
1919
1920         /**
1921          * Return the value accessible from the object by path. Any undefined traversals are ignored
1922          * @param {Object} obj starting object
1923          * @param {String} path path to traverse
1924          * @param {boolean} [bindFnToScope=true]
1925          * @returns {Object} value as accessible by path
1926          */
1927         //TODO(misko): this function needs to be removed
1928         function getter(obj, path, bindFnToScope) {
1929           if (!path) return obj;
1930           var keys = path.split('.');
1931           var key;
1932           var lastInstance = obj;
1933           var len = keys.length;
1934
1935           for (var i = 0; i < len; i++) {
1936             key = keys[i];
1937             if (obj) {
1938               obj = (lastInstance = obj)[key];
1939             }
1940           }
1941           if (!bindFnToScope && isFunction(obj)) {
1942             return bind(lastInstance, obj);
1943           }
1944           return obj;
1945         }
1946
1947         /**
1948          * Return the DOM siblings between the first and last node in the given array.
1949          * @param {Array} array like object
1950          * @returns {Array} the inputted object or a jqLite collection containing the nodes
1951          */
1952         function getBlockNodes(nodes) {
1953           // TODO(perf): update `nodes` instead of creating a new object?
1954           var node = nodes[0];
1955           var endNode = nodes[nodes.length - 1];
1956           var blockNodes;
1957
1958           for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
1959             if (blockNodes || nodes[i] !== node) {
1960               if (!blockNodes) {
1961                 blockNodes = jqLite(slice.call(nodes, 0, i));
1962               }
1963               blockNodes.push(node);
1964             }
1965           }
1966
1967           return blockNodes || nodes;
1968         }
1969
1970
1971         /**
1972          * Creates a new object without a prototype. This object is useful for lookup without having to
1973          * guard against prototypically inherited properties via hasOwnProperty.
1974          *
1975          * Related micro-benchmarks:
1976          * - http://jsperf.com/object-create2
1977          * - http://jsperf.com/proto-map-lookup/2
1978          * - http://jsperf.com/for-in-vs-object-keys2
1979          *
1980          * @returns {Object}
1981          */
1982         function createMap() {
1983           return Object.create(null);
1984         }
1985
1986         var NODE_TYPE_ELEMENT = 1;
1987         var NODE_TYPE_ATTRIBUTE = 2;
1988         var NODE_TYPE_TEXT = 3;
1989         var NODE_TYPE_COMMENT = 8;
1990         var NODE_TYPE_DOCUMENT = 9;
1991         var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1992
1993         /**
1994          * @ngdoc type
1995          * @name angular.Module
1996          * @module ng
1997          * @description
1998          *
1999          * Interface for configuring angular {@link angular.module modules}.
2000          */
2001
2002         function setupModuleLoader(window) {
2003
2004           var $injectorMinErr = minErr('$injector');
2005           var ngMinErr = minErr('ng');
2006
2007           function ensure(obj, name, factory) {
2008             return obj[name] || (obj[name] = factory());
2009           }
2010
2011           var angular = ensure(window, 'angular', Object);
2012
2013           // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
2014           angular.$$minErr = angular.$$minErr || minErr;
2015
2016           return ensure(angular, 'module', function() {
2017             /** @type {Object.<string, angular.Module>} */
2018             var modules = {};
2019
2020             /**
2021              * @ngdoc function
2022              * @name angular.module
2023              * @module ng
2024              * @description
2025              *
2026              * The `angular.module` is a global place for creating, registering and retrieving Angular
2027              * modules.
2028              * All modules (angular core or 3rd party) that should be available to an application must be
2029              * registered using this mechanism.
2030              *
2031              * Passing one argument retrieves an existing {@link angular.Module},
2032              * whereas passing more than one argument creates a new {@link angular.Module}
2033              *
2034              *
2035              * # Module
2036              *
2037              * A module is a collection of services, directives, controllers, filters, and configuration information.
2038              * `angular.module` is used to configure the {@link auto.$injector $injector}.
2039              *
2040              * ```js
2041              * // Create a new module
2042              * var myModule = angular.module('myModule', []);
2043              *
2044              * // register a new service
2045              * myModule.value('appName', 'MyCoolApp');
2046              *
2047              * // configure existing services inside initialization blocks.
2048              * myModule.config(['$locationProvider', function($locationProvider) {
2049              *   // Configure existing providers
2050              *   $locationProvider.hashPrefix('!');
2051              * }]);
2052              * ```
2053              *
2054              * Then you can create an injector and load your modules like this:
2055              *
2056              * ```js
2057              * var injector = angular.injector(['ng', 'myModule'])
2058              * ```
2059              *
2060              * However it's more likely that you'll just use
2061              * {@link ng.directive:ngApp ngApp} or
2062              * {@link angular.bootstrap} to simplify this process for you.
2063              *
2064              * @param {!string} name The name of the module to create or retrieve.
2065              * @param {!Array.<string>=} requires If specified then new module is being created. If
2066              *        unspecified then the module is being retrieved for further configuration.
2067              * @param {Function=} configFn Optional configuration function for the module. Same as
2068              *        {@link angular.Module#config Module#config()}.
2069              * @returns {module} new module with the {@link angular.Module} api.
2070              */
2071             return function module(name, requires, configFn) {
2072               var assertNotHasOwnProperty = function(name, context) {
2073                 if (name === 'hasOwnProperty') {
2074                   throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
2075                 }
2076               };
2077
2078               assertNotHasOwnProperty(name, 'module');
2079               if (requires && modules.hasOwnProperty(name)) {
2080                 modules[name] = null;
2081               }
2082               return ensure(modules, name, function() {
2083                 if (!requires) {
2084                   throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
2085                      "the module name or forgot to load it. If registering a module ensure that you " +
2086                      "specify the dependencies as the second argument.", name);
2087                 }
2088
2089                 /** @type {!Array.<Array.<*>>} */
2090                 var invokeQueue = [];
2091
2092                 /** @type {!Array.<Function>} */
2093                 var configBlocks = [];
2094
2095                 /** @type {!Array.<Function>} */
2096                 var runBlocks = [];
2097
2098                 var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
2099
2100                 /** @type {angular.Module} */
2101                 var moduleInstance = {
2102                   // Private state
2103                   _invokeQueue: invokeQueue,
2104                   _configBlocks: configBlocks,
2105                   _runBlocks: runBlocks,
2106
2107                   /**
2108                    * @ngdoc property
2109                    * @name angular.Module#requires
2110                    * @module ng
2111                    *
2112                    * @description
2113                    * Holds the list of modules which the injector will load before the current module is
2114                    * loaded.
2115                    */
2116                   requires: requires,
2117
2118                   /**
2119                    * @ngdoc property
2120                    * @name angular.Module#name
2121                    * @module ng
2122                    *
2123                    * @description
2124                    * Name of the module.
2125                    */
2126                   name: name,
2127
2128
2129                   /**
2130                    * @ngdoc method
2131                    * @name angular.Module#provider
2132                    * @module ng
2133                    * @param {string} name service name
2134                    * @param {Function} providerType Construction function for creating new instance of the
2135                    *                                service.
2136                    * @description
2137                    * See {@link auto.$provide#provider $provide.provider()}.
2138                    */
2139                   provider: invokeLaterAndSetModuleName('$provide', 'provider'),
2140
2141                   /**
2142                    * @ngdoc method
2143                    * @name angular.Module#factory
2144                    * @module ng
2145                    * @param {string} name service name
2146                    * @param {Function} providerFunction Function for creating new instance of the service.
2147                    * @description
2148                    * See {@link auto.$provide#factory $provide.factory()}.
2149                    */
2150                   factory: invokeLaterAndSetModuleName('$provide', 'factory'),
2151
2152                   /**
2153                    * @ngdoc method
2154                    * @name angular.Module#service
2155                    * @module ng
2156                    * @param {string} name service name
2157                    * @param {Function} constructor A constructor function that will be instantiated.
2158                    * @description
2159                    * See {@link auto.$provide#service $provide.service()}.
2160                    */
2161                   service: invokeLaterAndSetModuleName('$provide', 'service'),
2162
2163                   /**
2164                    * @ngdoc method
2165                    * @name angular.Module#value
2166                    * @module ng
2167                    * @param {string} name service name
2168                    * @param {*} object Service instance object.
2169                    * @description
2170                    * See {@link auto.$provide#value $provide.value()}.
2171                    */
2172                   value: invokeLater('$provide', 'value'),
2173
2174                   /**
2175                    * @ngdoc method
2176                    * @name angular.Module#constant
2177                    * @module ng
2178                    * @param {string} name constant name
2179                    * @param {*} object Constant value.
2180                    * @description
2181                    * Because the constants are fixed, they get applied before other provide methods.
2182                    * See {@link auto.$provide#constant $provide.constant()}.
2183                    */
2184                   constant: invokeLater('$provide', 'constant', 'unshift'),
2185
2186                    /**
2187                    * @ngdoc method
2188                    * @name angular.Module#decorator
2189                    * @module ng
2190                    * @param {string} The name of the service to decorate.
2191                    * @param {Function} This function will be invoked when the service needs to be
2192                    *                                    instantiated and should return the decorated service instance.
2193                    * @description
2194                    * See {@link auto.$provide#decorator $provide.decorator()}.
2195                    */
2196                   decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
2197
2198                   /**
2199                    * @ngdoc method
2200                    * @name angular.Module#animation
2201                    * @module ng
2202                    * @param {string} name animation name
2203                    * @param {Function} animationFactory Factory function for creating new instance of an
2204                    *                                    animation.
2205                    * @description
2206                    *
2207                    * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
2208                    *
2209                    *
2210                    * Defines an animation hook that can be later used with
2211                    * {@link $animate $animate} service and directives that use this service.
2212                    *
2213                    * ```js
2214                    * module.animation('.animation-name', function($inject1, $inject2) {
2215                    *   return {
2216                    *     eventName : function(element, done) {
2217                    *       //code to run the animation
2218                    *       //once complete, then run done()
2219                    *       return function cancellationFunction(element) {
2220                    *         //code to cancel the animation
2221                    *       }
2222                    *     }
2223                    *   }
2224                    * })
2225                    * ```
2226                    *
2227                    * See {@link ng.$animateProvider#register $animateProvider.register()} and
2228                    * {@link ngAnimate ngAnimate module} for more information.
2229                    */
2230                   animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
2231
2232                   /**
2233                    * @ngdoc method
2234                    * @name angular.Module#filter
2235                    * @module ng
2236                    * @param {string} name Filter name - this must be a valid angular expression identifier
2237                    * @param {Function} filterFactory Factory function for creating new instance of filter.
2238                    * @description
2239                    * See {@link ng.$filterProvider#register $filterProvider.register()}.
2240                    *
2241                    * <div class="alert alert-warning">
2242                    * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
2243                    * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
2244                    * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
2245                    * (`myapp_subsection_filterx`).
2246                    * </div>
2247                    */
2248                   filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
2249
2250                   /**
2251                    * @ngdoc method
2252                    * @name angular.Module#controller
2253                    * @module ng
2254                    * @param {string|Object} name Controller name, or an object map of controllers where the
2255                    *    keys are the names and the values are the constructors.
2256                    * @param {Function} constructor Controller constructor function.
2257                    * @description
2258                    * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
2259                    */
2260                   controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
2261
2262                   /**
2263                    * @ngdoc method
2264                    * @name angular.Module#directive
2265                    * @module ng
2266                    * @param {string|Object} name Directive name, or an object map of directives where the
2267                    *    keys are the names and the values are the factories.
2268                    * @param {Function} directiveFactory Factory function for creating new instance of
2269                    * directives.
2270                    * @description
2271                    * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
2272                    */
2273                   directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
2274
2275                   /**
2276                    * @ngdoc method
2277                    * @name angular.Module#config
2278                    * @module ng
2279                    * @param {Function} configFn Execute this function on module load. Useful for service
2280                    *    configuration.
2281                    * @description
2282                    * Use this method to register work which needs to be performed on module loading.
2283                    * For more about how to configure services, see
2284                    * {@link providers#provider-recipe Provider Recipe}.
2285                    */
2286                   config: config,
2287
2288                   /**
2289                    * @ngdoc method
2290                    * @name angular.Module#run
2291                    * @module ng
2292                    * @param {Function} initializationFn Execute this function after injector creation.
2293                    *    Useful for application initialization.
2294                    * @description
2295                    * Use this method to register work which should be performed when the injector is done
2296                    * loading all modules.
2297                    */
2298                   run: function(block) {
2299                     runBlocks.push(block);
2300                     return this;
2301                   }
2302                 };
2303
2304                 if (configFn) {
2305                   config(configFn);
2306                 }
2307
2308                 return moduleInstance;
2309
2310                 /**
2311                  * @param {string} provider
2312                  * @param {string} method
2313                  * @param {String=} insertMethod
2314                  * @returns {angular.Module}
2315                  */
2316                 function invokeLater(provider, method, insertMethod, queue) {
2317                   if (!queue) queue = invokeQueue;
2318                   return function() {
2319                     queue[insertMethod || 'push']([provider, method, arguments]);
2320                     return moduleInstance;
2321                   };
2322                 }
2323
2324                 /**
2325                  * @param {string} provider
2326                  * @param {string} method
2327                  * @returns {angular.Module}
2328                  */
2329                 function invokeLaterAndSetModuleName(provider, method) {
2330                   return function(recipeName, factoryFunction) {
2331                     if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
2332                     invokeQueue.push([provider, method, arguments]);
2333                     return moduleInstance;
2334                   };
2335                 }
2336               });
2337             };
2338           });
2339
2340         }
2341
2342         /* global: toDebugString: true */
2343
2344         function serializeObject(obj) {
2345           var seen = [];
2346
2347           return JSON.stringify(obj, function(key, val) {
2348             val = toJsonReplacer(key, val);
2349             if (isObject(val)) {
2350
2351               if (seen.indexOf(val) >= 0) return '...';
2352
2353               seen.push(val);
2354             }
2355             return val;
2356           });
2357         }
2358
2359         function toDebugString(obj) {
2360           if (typeof obj === 'function') {
2361             return obj.toString().replace(/ \{[\s\S]*$/, '');
2362           } else if (isUndefined(obj)) {
2363             return 'undefined';
2364           } else if (typeof obj !== 'string') {
2365             return serializeObject(obj);
2366           }
2367           return obj;
2368         }
2369
2370         /* global angularModule: true,
2371           version: true,
2372
2373           $CompileProvider,
2374
2375           htmlAnchorDirective,
2376           inputDirective,
2377           inputDirective,
2378           formDirective,
2379           scriptDirective,
2380           selectDirective,
2381           styleDirective,
2382           optionDirective,
2383           ngBindDirective,
2384           ngBindHtmlDirective,
2385           ngBindTemplateDirective,
2386           ngClassDirective,
2387           ngClassEvenDirective,
2388           ngClassOddDirective,
2389           ngCloakDirective,
2390           ngControllerDirective,
2391           ngFormDirective,
2392           ngHideDirective,
2393           ngIfDirective,
2394           ngIncludeDirective,
2395           ngIncludeFillContentDirective,
2396           ngInitDirective,
2397           ngNonBindableDirective,
2398           ngPluralizeDirective,
2399           ngRepeatDirective,
2400           ngShowDirective,
2401           ngStyleDirective,
2402           ngSwitchDirective,
2403           ngSwitchWhenDirective,
2404           ngSwitchDefaultDirective,
2405           ngOptionsDirective,
2406           ngTranscludeDirective,
2407           ngModelDirective,
2408           ngListDirective,
2409           ngChangeDirective,
2410           patternDirective,
2411           patternDirective,
2412           requiredDirective,
2413           requiredDirective,
2414           minlengthDirective,
2415           minlengthDirective,
2416           maxlengthDirective,
2417           maxlengthDirective,
2418           ngValueDirective,
2419           ngModelOptionsDirective,
2420           ngAttributeAliasDirectives,
2421           ngEventDirectives,
2422
2423           $AnchorScrollProvider,
2424           $AnimateProvider,
2425           $CoreAnimateCssProvider,
2426           $$CoreAnimateQueueProvider,
2427           $$CoreAnimateRunnerProvider,
2428           $BrowserProvider,
2429           $CacheFactoryProvider,
2430           $ControllerProvider,
2431           $DocumentProvider,
2432           $ExceptionHandlerProvider,
2433           $FilterProvider,
2434           $$ForceReflowProvider,
2435           $InterpolateProvider,
2436           $IntervalProvider,
2437           $$HashMapProvider,
2438           $HttpProvider,
2439           $HttpParamSerializerProvider,
2440           $HttpParamSerializerJQLikeProvider,
2441           $HttpBackendProvider,
2442           $xhrFactoryProvider,
2443           $LocationProvider,
2444           $LogProvider,
2445           $ParseProvider,
2446           $RootScopeProvider,
2447           $QProvider,
2448           $$QProvider,
2449           $$SanitizeUriProvider,
2450           $SceProvider,
2451           $SceDelegateProvider,
2452           $SnifferProvider,
2453           $TemplateCacheProvider,
2454           $TemplateRequestProvider,
2455           $$TestabilityProvider,
2456           $TimeoutProvider,
2457           $$RAFProvider,
2458           $WindowProvider,
2459           $$jqLiteProvider,
2460           $$CookieReaderProvider
2461         */
2462
2463
2464         /**
2465          * @ngdoc object
2466          * @name angular.version
2467          * @module ng
2468          * @description
2469          * An object that contains information about the current AngularJS version.
2470          *
2471          * This object has the following properties:
2472          *
2473          * - `full` – `{string}` – Full version string, such as "0.9.18".
2474          * - `major` – `{number}` – Major version number, such as "0".
2475          * - `minor` – `{number}` – Minor version number, such as "9".
2476          * - `dot` – `{number}` – Dot version number, such as "18".
2477          * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2478          */
2479         var version = {
2480           full: '1.4.8',    // all of these placeholder strings will be replaced by grunt's
2481           major: 1,    // package task
2482           minor: 4,
2483           dot: 8,
2484           codeName: 'ice-manipulation'
2485         };
2486
2487
2488         function publishExternalAPI(angular) {
2489           extend(angular, {
2490             'bootstrap': bootstrap,
2491             'copy': copy,
2492             'extend': extend,
2493             'merge': merge,
2494             'equals': equals,
2495             'element': jqLite,
2496             'forEach': forEach,
2497             'injector': createInjector,
2498             'noop': noop,
2499             'bind': bind,
2500             'toJson': toJson,
2501             'fromJson': fromJson,
2502             'identity': identity,
2503             'isUndefined': isUndefined,
2504             'isDefined': isDefined,
2505             'isString': isString,
2506             'isFunction': isFunction,
2507             'isObject': isObject,
2508             'isNumber': isNumber,
2509             'isElement': isElement,
2510             'isArray': isArray,
2511             'version': version,
2512             'isDate': isDate,
2513             'lowercase': lowercase,
2514             'uppercase': uppercase,
2515             'callbacks': {counter: 0},
2516             'getTestability': getTestability,
2517             '$$minErr': minErr,
2518             '$$csp': csp,
2519             'reloadWithDebugInfo': reloadWithDebugInfo
2520           });
2521
2522           angularModule = setupModuleLoader(window);
2523
2524           angularModule('ng', ['ngLocale'], ['$provide',
2525             function ngModule($provide) {
2526               // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2527               $provide.provider({
2528                 $$sanitizeUri: $$SanitizeUriProvider
2529               });
2530               $provide.provider('$compile', $CompileProvider).
2531                 directive({
2532                     a: htmlAnchorDirective,
2533                     input: inputDirective,
2534                     textarea: inputDirective,
2535                     form: formDirective,
2536                     script: scriptDirective,
2537                     select: selectDirective,
2538                     style: styleDirective,
2539                     option: optionDirective,
2540                     ngBind: ngBindDirective,
2541                     ngBindHtml: ngBindHtmlDirective,
2542                     ngBindTemplate: ngBindTemplateDirective,
2543                     ngClass: ngClassDirective,
2544                     ngClassEven: ngClassEvenDirective,
2545                     ngClassOdd: ngClassOddDirective,
2546                     ngCloak: ngCloakDirective,
2547                     ngController: ngControllerDirective,
2548                     ngForm: ngFormDirective,
2549                     ngHide: ngHideDirective,
2550                     ngIf: ngIfDirective,
2551                     ngInclude: ngIncludeDirective,
2552                     ngInit: ngInitDirective,
2553                     ngNonBindable: ngNonBindableDirective,
2554                     ngPluralize: ngPluralizeDirective,
2555                     ngRepeat: ngRepeatDirective,
2556                     ngShow: ngShowDirective,
2557                     ngStyle: ngStyleDirective,
2558                     ngSwitch: ngSwitchDirective,
2559                     ngSwitchWhen: ngSwitchWhenDirective,
2560                     ngSwitchDefault: ngSwitchDefaultDirective,
2561                     ngOptions: ngOptionsDirective,
2562                     ngTransclude: ngTranscludeDirective,
2563                     ngModel: ngModelDirective,
2564                     ngList: ngListDirective,
2565                     ngChange: ngChangeDirective,
2566                     pattern: patternDirective,
2567                     ngPattern: patternDirective,
2568                     required: requiredDirective,
2569                     ngRequired: requiredDirective,
2570                     minlength: minlengthDirective,
2571                     ngMinlength: minlengthDirective,
2572                     maxlength: maxlengthDirective,
2573                     ngMaxlength: maxlengthDirective,
2574                     ngValue: ngValueDirective,
2575                     ngModelOptions: ngModelOptionsDirective
2576                 }).
2577                 directive({
2578                   ngInclude: ngIncludeFillContentDirective
2579                 }).
2580                 directive(ngAttributeAliasDirectives).
2581                 directive(ngEventDirectives);
2582               $provide.provider({
2583                 $anchorScroll: $AnchorScrollProvider,
2584                 $animate: $AnimateProvider,
2585                 $animateCss: $CoreAnimateCssProvider,
2586                 $$animateQueue: $$CoreAnimateQueueProvider,
2587                 $$AnimateRunner: $$CoreAnimateRunnerProvider,
2588                 $browser: $BrowserProvider,
2589                 $cacheFactory: $CacheFactoryProvider,
2590                 $controller: $ControllerProvider,
2591                 $document: $DocumentProvider,
2592                 $exceptionHandler: $ExceptionHandlerProvider,
2593                 $filter: $FilterProvider,
2594                 $$forceReflow: $$ForceReflowProvider,
2595                 $interpolate: $InterpolateProvider,
2596                 $interval: $IntervalProvider,
2597                 $http: $HttpProvider,
2598                 $httpParamSerializer: $HttpParamSerializerProvider,
2599                 $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
2600                 $httpBackend: $HttpBackendProvider,
2601                 $xhrFactory: $xhrFactoryProvider,
2602                 $location: $LocationProvider,
2603                 $log: $LogProvider,
2604                 $parse: $ParseProvider,
2605                 $rootScope: $RootScopeProvider,
2606                 $q: $QProvider,
2607                 $$q: $$QProvider,
2608                 $sce: $SceProvider,
2609                 $sceDelegate: $SceDelegateProvider,
2610                 $sniffer: $SnifferProvider,
2611                 $templateCache: $TemplateCacheProvider,
2612                 $templateRequest: $TemplateRequestProvider,
2613                 $$testability: $$TestabilityProvider,
2614                 $timeout: $TimeoutProvider,
2615                 $window: $WindowProvider,
2616                 $$rAF: $$RAFProvider,
2617                 $$jqLite: $$jqLiteProvider,
2618                 $$HashMap: $$HashMapProvider,
2619                 $$cookieReader: $$CookieReaderProvider
2620               });
2621             }
2622           ]);
2623         }
2624
2625         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2626          *     Any commits to this file should be reviewed with security in mind.  *
2627          *   Changes to this file can potentially create security vulnerabilities. *
2628          *          An approval from 2 Core members with history of modifying      *
2629          *                         this file is required.                          *
2630          *                                                                         *
2631          *  Does the change somehow allow for arbitrary javascript to be executed? *
2632          *    Or allows for someone to change the prototype of built-in objects?   *
2633          *     Or gives undesired access to variables likes document or window?    *
2634          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2635
2636         /* global JQLitePrototype: true,
2637           addEventListenerFn: true,
2638           removeEventListenerFn: true,
2639           BOOLEAN_ATTR: true,
2640           ALIASED_ATTR: true,
2641         */
2642
2643         //////////////////////////////////
2644         //JQLite
2645         //////////////////////////////////
2646
2647         /**
2648          * @ngdoc function
2649          * @name angular.element
2650          * @module ng
2651          * @kind function
2652          *
2653          * @description
2654          * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2655          *
2656          * If jQuery is available, `angular.element` is an alias for the
2657          * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2658          * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2659          *
2660          * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2661          * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2662          * commonly needed functionality with the goal of having a very small footprint.</div>
2663          *
2664          * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
2665          *
2666          * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2667          * jqLite; they are never raw DOM references.</div>
2668          *
2669          * ## Angular's jqLite
2670          * jqLite provides only the following jQuery methods:
2671          *
2672          * - [`addClass()`](http://api.jquery.com/addClass/)
2673          * - [`after()`](http://api.jquery.com/after/)
2674          * - [`append()`](http://api.jquery.com/append/)
2675          * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2676          * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2677          * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2678          * - [`clone()`](http://api.jquery.com/clone/)
2679          * - [`contents()`](http://api.jquery.com/contents/)
2680          * - [`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'.
2681          * - [`data()`](http://api.jquery.com/data/)
2682          * - [`detach()`](http://api.jquery.com/detach/)
2683          * - [`empty()`](http://api.jquery.com/empty/)
2684          * - [`eq()`](http://api.jquery.com/eq/)
2685          * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2686          * - [`hasClass()`](http://api.jquery.com/hasClass/)
2687          * - [`html()`](http://api.jquery.com/html/)
2688          * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2689          * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2690          * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
2691          * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2692          * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2693          * - [`prepend()`](http://api.jquery.com/prepend/)
2694          * - [`prop()`](http://api.jquery.com/prop/)
2695          * - [`ready()`](http://api.jquery.com/ready/)
2696          * - [`remove()`](http://api.jquery.com/remove/)
2697          * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2698          * - [`removeClass()`](http://api.jquery.com/removeClass/)
2699          * - [`removeData()`](http://api.jquery.com/removeData/)
2700          * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2701          * - [`text()`](http://api.jquery.com/text/)
2702          * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2703          * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2704          * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
2705          * - [`val()`](http://api.jquery.com/val/)
2706          * - [`wrap()`](http://api.jquery.com/wrap/)
2707          *
2708          * ## jQuery/jqLite Extras
2709          * Angular also provides the following additional methods and events to both jQuery and jqLite:
2710          *
2711          * ### Events
2712          * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2713          *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2714          *    element before it is removed.
2715          *
2716          * ### Methods
2717          * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2718          *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2719          *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2720          *   `'ngModel'`).
2721          * - `injector()` - retrieves the injector of the current element or its parent.
2722          * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2723          *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2724          *   be enabled.
2725          * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2726          *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2727          *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2728          *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2729          * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2730          *   parent element is reached.
2731          *
2732          * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2733          * @returns {Object} jQuery object.
2734          */
2735
2736         JQLite.expando = 'ng339';
2737
2738         var jqCache = JQLite.cache = {},
2739             jqId = 1,
2740             addEventListenerFn = function(element, type, fn) {
2741               element.addEventListener(type, fn, false);
2742             },
2743             removeEventListenerFn = function(element, type, fn) {
2744               element.removeEventListener(type, fn, false);
2745             };
2746
2747         /*
2748          * !!! This is an undocumented "private" function !!!
2749          */
2750         JQLite._data = function(node) {
2751           //jQuery always returns an object on cache miss
2752           return this.cache[node[this.expando]] || {};
2753         };
2754
2755         function jqNextId() { return ++jqId; }
2756
2757
2758         var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2759         var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2760         var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2761         var jqLiteMinErr = minErr('jqLite');
2762
2763         /**
2764          * Converts snake_case to camelCase.
2765          * Also there is special case for Moz prefix starting with upper case letter.
2766          * @param name Name to normalize
2767          */
2768         function camelCase(name) {
2769           return name.
2770             replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2771               return offset ? letter.toUpperCase() : letter;
2772             }).
2773             replace(MOZ_HACK_REGEXP, 'Moz$1');
2774         }
2775
2776         var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
2777         var HTML_REGEXP = /<|&#?\w+;/;
2778         var TAG_NAME_REGEXP = /<([\w:-]+)/;
2779         var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
2780
2781         var wrapMap = {
2782           'option': [1, '<select multiple="multiple">', '</select>'],
2783
2784           'thead': [1, '<table>', '</table>'],
2785           'col': [2, '<table><colgroup>', '</colgroup></table>'],
2786           'tr': [2, '<table><tbody>', '</tbody></table>'],
2787           'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2788           '_default': [0, "", ""]
2789         };
2790
2791         wrapMap.optgroup = wrapMap.option;
2792         wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2793         wrapMap.th = wrapMap.td;
2794
2795
2796         function jqLiteIsTextNode(html) {
2797           return !HTML_REGEXP.test(html);
2798         }
2799
2800         function jqLiteAcceptsData(node) {
2801           // The window object can accept data but has no nodeType
2802           // Otherwise we are only interested in elements (1) and documents (9)
2803           var nodeType = node.nodeType;
2804           return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2805         }
2806
2807         function jqLiteHasData(node) {
2808           for (var key in jqCache[node.ng339]) {
2809             return true;
2810           }
2811           return false;
2812         }
2813
2814         function jqLiteBuildFragment(html, context) {
2815           var tmp, tag, wrap,
2816               fragment = context.createDocumentFragment(),
2817               nodes = [], i;
2818
2819           if (jqLiteIsTextNode(html)) {
2820             // Convert non-html into a text node
2821             nodes.push(context.createTextNode(html));
2822           } else {
2823             // Convert html into DOM nodes
2824             tmp = tmp || fragment.appendChild(context.createElement("div"));
2825             tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2826             wrap = wrapMap[tag] || wrapMap._default;
2827             tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2828
2829             // Descend through wrappers to the right content
2830             i = wrap[0];
2831             while (i--) {
2832               tmp = tmp.lastChild;
2833             }
2834
2835             nodes = concat(nodes, tmp.childNodes);
2836
2837             tmp = fragment.firstChild;
2838             tmp.textContent = "";
2839           }
2840
2841           // Remove wrapper from fragment
2842           fragment.textContent = "";
2843           fragment.innerHTML = ""; // Clear inner HTML
2844           forEach(nodes, function(node) {
2845             fragment.appendChild(node);
2846           });
2847
2848           return fragment;
2849         }
2850
2851         function jqLiteParseHTML(html, context) {
2852           context = context || document;
2853           var parsed;
2854
2855           if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2856             return [context.createElement(parsed[1])];
2857           }
2858
2859           if ((parsed = jqLiteBuildFragment(html, context))) {
2860             return parsed.childNodes;
2861           }
2862
2863           return [];
2864         }
2865
2866
2867         // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2868         var jqLiteContains = Node.prototype.contains || function(arg) {
2869           // jshint bitwise: false
2870           return !!(this.compareDocumentPosition(arg) & 16);
2871           // jshint bitwise: true
2872         };
2873
2874         /////////////////////////////////////////////
2875         function JQLite(element) {
2876           if (element instanceof JQLite) {
2877             return element;
2878           }
2879
2880           var argIsString;
2881
2882           if (isString(element)) {
2883             element = trim(element);
2884             argIsString = true;
2885           }
2886           if (!(this instanceof JQLite)) {
2887             if (argIsString && element.charAt(0) != '<') {
2888               throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2889             }
2890             return new JQLite(element);
2891           }
2892
2893           if (argIsString) {
2894             jqLiteAddNodes(this, jqLiteParseHTML(element));
2895           } else {
2896             jqLiteAddNodes(this, element);
2897           }
2898         }
2899
2900         function jqLiteClone(element) {
2901           return element.cloneNode(true);
2902         }
2903
2904         function jqLiteDealoc(element, onlyDescendants) {
2905           if (!onlyDescendants) jqLiteRemoveData(element);
2906
2907           if (element.querySelectorAll) {
2908             var descendants = element.querySelectorAll('*');
2909             for (var i = 0, l = descendants.length; i < l; i++) {
2910               jqLiteRemoveData(descendants[i]);
2911             }
2912           }
2913         }
2914
2915         function jqLiteOff(element, type, fn, unsupported) {
2916           if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2917
2918           var expandoStore = jqLiteExpandoStore(element);
2919           var events = expandoStore && expandoStore.events;
2920           var handle = expandoStore && expandoStore.handle;
2921
2922           if (!handle) return; //no listeners registered
2923
2924           if (!type) {
2925             for (type in events) {
2926               if (type !== '$destroy') {
2927                 removeEventListenerFn(element, type, handle);
2928               }
2929               delete events[type];
2930             }
2931           } else {
2932
2933             var removeHandler = function(type) {
2934               var listenerFns = events[type];
2935               if (isDefined(fn)) {
2936                 arrayRemove(listenerFns || [], fn);
2937               }
2938               if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
2939                 removeEventListenerFn(element, type, handle);
2940                 delete events[type];
2941               }
2942             };
2943
2944             forEach(type.split(' '), function(type) {
2945               removeHandler(type);
2946               if (MOUSE_EVENT_MAP[type]) {
2947                 removeHandler(MOUSE_EVENT_MAP[type]);
2948               }
2949             });
2950           }
2951         }
2952
2953         function jqLiteRemoveData(element, name) {
2954           var expandoId = element.ng339;
2955           var expandoStore = expandoId && jqCache[expandoId];
2956
2957           if (expandoStore) {
2958             if (name) {
2959               delete expandoStore.data[name];
2960               return;
2961             }
2962
2963             if (expandoStore.handle) {
2964               if (expandoStore.events.$destroy) {
2965                 expandoStore.handle({}, '$destroy');
2966               }
2967               jqLiteOff(element);
2968             }
2969             delete jqCache[expandoId];
2970             element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2971           }
2972         }
2973
2974
2975         function jqLiteExpandoStore(element, createIfNecessary) {
2976           var expandoId = element.ng339,
2977               expandoStore = expandoId && jqCache[expandoId];
2978
2979           if (createIfNecessary && !expandoStore) {
2980             element.ng339 = expandoId = jqNextId();
2981             expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
2982           }
2983
2984           return expandoStore;
2985         }
2986
2987
2988         function jqLiteData(element, key, value) {
2989           if (jqLiteAcceptsData(element)) {
2990
2991             var isSimpleSetter = isDefined(value);
2992             var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
2993             var massGetter = !key;
2994             var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
2995             var data = expandoStore && expandoStore.data;
2996
2997             if (isSimpleSetter) { // data('key', value)
2998               data[key] = value;
2999             } else {
3000               if (massGetter) {  // data()
3001                 return data;
3002               } else {
3003                 if (isSimpleGetter) { // data('key')
3004                   // don't force creation of expandoStore if it doesn't exist yet
3005                   return data && data[key];
3006                 } else { // mass-setter: data({key1: val1, key2: val2})
3007                   extend(data, key);
3008                 }
3009               }
3010             }
3011           }
3012         }
3013
3014         function jqLiteHasClass(element, selector) {
3015           if (!element.getAttribute) return false;
3016           return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
3017               indexOf(" " + selector + " ") > -1);
3018         }
3019
3020         function jqLiteRemoveClass(element, cssClasses) {
3021           if (cssClasses && element.setAttribute) {
3022             forEach(cssClasses.split(' '), function(cssClass) {
3023               element.setAttribute('class', trim(
3024                   (" " + (element.getAttribute('class') || '') + " ")
3025                   .replace(/[\n\t]/g, " ")
3026                   .replace(" " + trim(cssClass) + " ", " "))
3027               );
3028             });
3029           }
3030         }
3031
3032         function jqLiteAddClass(element, cssClasses) {
3033           if (cssClasses && element.setAttribute) {
3034             var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
3035                                     .replace(/[\n\t]/g, " ");
3036
3037             forEach(cssClasses.split(' '), function(cssClass) {
3038               cssClass = trim(cssClass);
3039               if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
3040                 existingClasses += cssClass + ' ';
3041               }
3042             });
3043
3044             element.setAttribute('class', trim(existingClasses));
3045           }
3046         }
3047
3048
3049         function jqLiteAddNodes(root, elements) {
3050           // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
3051
3052           if (elements) {
3053
3054             // if a Node (the most common case)
3055             if (elements.nodeType) {
3056               root[root.length++] = elements;
3057             } else {
3058               var length = elements.length;
3059
3060               // if an Array or NodeList and not a Window
3061               if (typeof length === 'number' && elements.window !== elements) {
3062                 if (length) {
3063                   for (var i = 0; i < length; i++) {
3064                     root[root.length++] = elements[i];
3065                   }
3066                 }
3067               } else {
3068                 root[root.length++] = elements;
3069               }
3070             }
3071           }
3072         }
3073
3074
3075         function jqLiteController(element, name) {
3076           return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
3077         }
3078
3079         function jqLiteInheritedData(element, name, value) {
3080           // if element is the document object work with the html element instead
3081           // this makes $(document).scope() possible
3082           if (element.nodeType == NODE_TYPE_DOCUMENT) {
3083             element = element.documentElement;
3084           }
3085           var names = isArray(name) ? name : [name];
3086
3087           while (element) {
3088             for (var i = 0, ii = names.length; i < ii; i++) {
3089               if (isDefined(value = jqLite.data(element, names[i]))) return value;
3090             }
3091
3092             // If dealing with a document fragment node with a host element, and no parent, use the host
3093             // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
3094             // to lookup parent controllers.
3095             element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
3096           }
3097         }
3098
3099         function jqLiteEmpty(element) {
3100           jqLiteDealoc(element, true);
3101           while (element.firstChild) {
3102             element.removeChild(element.firstChild);
3103           }
3104         }
3105
3106         function jqLiteRemove(element, keepData) {
3107           if (!keepData) jqLiteDealoc(element);
3108           var parent = element.parentNode;
3109           if (parent) parent.removeChild(element);
3110         }
3111
3112
3113         function jqLiteDocumentLoaded(action, win) {
3114           win = win || window;
3115           if (win.document.readyState === 'complete') {
3116             // Force the action to be run async for consistent behaviour
3117             // from the action's point of view
3118             // i.e. it will definitely not be in a $apply
3119             win.setTimeout(action);
3120           } else {
3121             // No need to unbind this handler as load is only ever called once
3122             jqLite(win).on('load', action);
3123           }
3124         }
3125
3126         //////////////////////////////////////////
3127         // Functions which are declared directly.
3128         //////////////////////////////////////////
3129         var JQLitePrototype = JQLite.prototype = {
3130           ready: function(fn) {
3131             var fired = false;
3132
3133             function trigger() {
3134               if (fired) return;
3135               fired = true;
3136               fn();
3137             }
3138
3139             // check if document is already loaded
3140             if (document.readyState === 'complete') {
3141               setTimeout(trigger);
3142             } else {
3143               this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
3144               // we can not use jqLite since we are not done loading and jQuery could be loaded later.
3145               // jshint -W064
3146               JQLite(window).on('load', trigger); // fallback to window.onload for others
3147               // jshint +W064
3148             }
3149           },
3150           toString: function() {
3151             var value = [];
3152             forEach(this, function(e) { value.push('' + e);});
3153             return '[' + value.join(', ') + ']';
3154           },
3155
3156           eq: function(index) {
3157               return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
3158           },
3159
3160           length: 0,
3161           push: push,
3162           sort: [].sort,
3163           splice: [].splice
3164         };
3165
3166         //////////////////////////////////////////
3167         // Functions iterating getter/setters.
3168         // these functions return self on setter and
3169         // value on get.
3170         //////////////////////////////////////////
3171         var BOOLEAN_ATTR = {};
3172         forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
3173           BOOLEAN_ATTR[lowercase(value)] = value;
3174         });
3175         var BOOLEAN_ELEMENTS = {};
3176         forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
3177           BOOLEAN_ELEMENTS[value] = true;
3178         });
3179         var ALIASED_ATTR = {
3180           'ngMinlength': 'minlength',
3181           'ngMaxlength': 'maxlength',
3182           'ngMin': 'min',
3183           'ngMax': 'max',
3184           'ngPattern': 'pattern'
3185         };
3186
3187         function getBooleanAttrName(element, name) {
3188           // check dom last since we will most likely fail on name
3189           var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
3190
3191           // booleanAttr is here twice to minimize DOM access
3192           return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
3193         }
3194
3195         function getAliasedAttrName(name) {
3196           return ALIASED_ATTR[name];
3197         }
3198
3199         forEach({
3200           data: jqLiteData,
3201           removeData: jqLiteRemoveData,
3202           hasData: jqLiteHasData
3203         }, function(fn, name) {
3204           JQLite[name] = fn;
3205         });
3206
3207         forEach({
3208           data: jqLiteData,
3209           inheritedData: jqLiteInheritedData,
3210
3211           scope: function(element) {
3212             // Can't use jqLiteData here directly so we stay compatible with jQuery!
3213             return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
3214           },
3215
3216           isolateScope: function(element) {
3217             // Can't use jqLiteData here directly so we stay compatible with jQuery!
3218             return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
3219           },
3220
3221           controller: jqLiteController,
3222
3223           injector: function(element) {
3224             return jqLiteInheritedData(element, '$injector');
3225           },
3226
3227           removeAttr: function(element, name) {
3228             element.removeAttribute(name);
3229           },
3230
3231           hasClass: jqLiteHasClass,
3232
3233           css: function(element, name, value) {
3234             name = camelCase(name);
3235
3236             if (isDefined(value)) {
3237               element.style[name] = value;
3238             } else {
3239               return element.style[name];
3240             }
3241           },
3242
3243           attr: function(element, name, value) {
3244             var nodeType = element.nodeType;
3245             if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
3246               return;
3247             }
3248             var lowercasedName = lowercase(name);
3249             if (BOOLEAN_ATTR[lowercasedName]) {
3250               if (isDefined(value)) {
3251                 if (!!value) {
3252                   element[name] = true;
3253                   element.setAttribute(name, lowercasedName);
3254                 } else {
3255                   element[name] = false;
3256                   element.removeAttribute(lowercasedName);
3257                 }
3258               } else {
3259                 return (element[name] ||
3260                          (element.attributes.getNamedItem(name) || noop).specified)
3261                        ? lowercasedName
3262                        : undefined;
3263               }
3264             } else if (isDefined(value)) {
3265               element.setAttribute(name, value);
3266             } else if (element.getAttribute) {
3267               // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
3268               // some elements (e.g. Document) don't have get attribute, so return undefined
3269               var ret = element.getAttribute(name, 2);
3270               // normalize non-existing attributes to undefined (as jQuery)
3271               return ret === null ? undefined : ret;
3272             }
3273           },
3274
3275           prop: function(element, name, value) {
3276             if (isDefined(value)) {
3277               element[name] = value;
3278             } else {
3279               return element[name];
3280             }
3281           },
3282
3283           text: (function() {
3284             getText.$dv = '';
3285             return getText;
3286
3287             function getText(element, value) {
3288               if (isUndefined(value)) {
3289                 var nodeType = element.nodeType;
3290                 return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
3291               }
3292               element.textContent = value;
3293             }
3294           })(),
3295
3296           val: function(element, value) {
3297             if (isUndefined(value)) {
3298               if (element.multiple && nodeName_(element) === 'select') {
3299                 var result = [];
3300                 forEach(element.options, function(option) {
3301                   if (option.selected) {
3302                     result.push(option.value || option.text);
3303                   }
3304                 });
3305                 return result.length === 0 ? null : result;
3306               }
3307               return element.value;
3308             }
3309             element.value = value;
3310           },
3311
3312           html: function(element, value) {
3313             if (isUndefined(value)) {
3314               return element.innerHTML;
3315             }
3316             jqLiteDealoc(element, true);
3317             element.innerHTML = value;
3318           },
3319
3320           empty: jqLiteEmpty
3321         }, function(fn, name) {
3322           /**
3323            * Properties: writes return selection, reads return first value
3324            */
3325           JQLite.prototype[name] = function(arg1, arg2) {
3326             var i, key;
3327             var nodeCount = this.length;
3328
3329             // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
3330             // in a way that survives minification.
3331             // jqLiteEmpty takes no arguments but is a setter.
3332             if (fn !== jqLiteEmpty &&
3333                 (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
3334               if (isObject(arg1)) {
3335
3336                 // we are a write, but the object properties are the key/values
3337                 for (i = 0; i < nodeCount; i++) {
3338                   if (fn === jqLiteData) {
3339                     // data() takes the whole object in jQuery
3340                     fn(this[i], arg1);
3341                   } else {
3342                     for (key in arg1) {
3343                       fn(this[i], key, arg1[key]);
3344                     }
3345                   }
3346                 }
3347                 // return self for chaining
3348                 return this;
3349               } else {
3350                 // we are a read, so read the first child.
3351                 // TODO: do we still need this?
3352                 var value = fn.$dv;
3353                 // Only if we have $dv do we iterate over all, otherwise it is just the first element.
3354                 var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
3355                 for (var j = 0; j < jj; j++) {
3356                   var nodeValue = fn(this[j], arg1, arg2);
3357                   value = value ? value + nodeValue : nodeValue;
3358                 }
3359                 return value;
3360               }
3361             } else {
3362               // we are a write, so apply to all children
3363               for (i = 0; i < nodeCount; i++) {
3364                 fn(this[i], arg1, arg2);
3365               }
3366               // return self for chaining
3367               return this;
3368             }
3369           };
3370         });
3371
3372         function createEventHandler(element, events) {
3373           var eventHandler = function(event, type) {
3374             // jQuery specific api
3375             event.isDefaultPrevented = function() {
3376               return event.defaultPrevented;
3377             };
3378
3379             var eventFns = events[type || event.type];
3380             var eventFnsLength = eventFns ? eventFns.length : 0;
3381
3382             if (!eventFnsLength) return;
3383
3384             if (isUndefined(event.immediatePropagationStopped)) {
3385               var originalStopImmediatePropagation = event.stopImmediatePropagation;
3386               event.stopImmediatePropagation = function() {
3387                 event.immediatePropagationStopped = true;
3388
3389                 if (event.stopPropagation) {
3390                   event.stopPropagation();
3391                 }
3392
3393                 if (originalStopImmediatePropagation) {
3394                   originalStopImmediatePropagation.call(event);
3395                 }
3396               };
3397             }
3398
3399             event.isImmediatePropagationStopped = function() {
3400               return event.immediatePropagationStopped === true;
3401             };
3402
3403             // Some events have special handlers that wrap the real handler
3404             var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
3405
3406             // Copy event handlers in case event handlers array is modified during execution.
3407             if ((eventFnsLength > 1)) {
3408               eventFns = shallowCopy(eventFns);
3409             }
3410
3411             for (var i = 0; i < eventFnsLength; i++) {
3412               if (!event.isImmediatePropagationStopped()) {
3413                 handlerWrapper(element, event, eventFns[i]);
3414               }
3415             }
3416           };
3417
3418           // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3419           //       events on `element`
3420           eventHandler.elem = element;
3421           return eventHandler;
3422         }
3423
3424         function defaultHandlerWrapper(element, event, handler) {
3425           handler.call(element, event);
3426         }
3427
3428         function specialMouseHandlerWrapper(target, event, handler) {
3429           // Refer to jQuery's implementation of mouseenter & mouseleave
3430           // Read about mouseenter and mouseleave:
3431           // http://www.quirksmode.org/js/events_mouse.html#link8
3432           var related = event.relatedTarget;
3433           // For mousenter/leave call the handler if related is outside the target.
3434           // NB: No relatedTarget if the mouse left/entered the browser window
3435           if (!related || (related !== target && !jqLiteContains.call(target, related))) {
3436             handler.call(target, event);
3437           }
3438         }
3439
3440         //////////////////////////////////////////
3441         // Functions iterating traversal.
3442         // These functions chain results into a single
3443         // selector.
3444         //////////////////////////////////////////
3445         forEach({
3446           removeData: jqLiteRemoveData,
3447
3448           on: function jqLiteOn(element, type, fn, unsupported) {
3449             if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3450
3451             // Do not add event handlers to non-elements because they will not be cleaned up.
3452             if (!jqLiteAcceptsData(element)) {
3453               return;
3454             }
3455
3456             var expandoStore = jqLiteExpandoStore(element, true);
3457             var events = expandoStore.events;
3458             var handle = expandoStore.handle;
3459
3460             if (!handle) {
3461               handle = expandoStore.handle = createEventHandler(element, events);
3462             }
3463
3464             // http://jsperf.com/string-indexof-vs-split
3465             var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3466             var i = types.length;
3467
3468             var addHandler = function(type, specialHandlerWrapper, noEventListener) {
3469               var eventFns = events[type];
3470
3471               if (!eventFns) {
3472                 eventFns = events[type] = [];
3473                 eventFns.specialHandlerWrapper = specialHandlerWrapper;
3474                 if (type !== '$destroy' && !noEventListener) {
3475                   addEventListenerFn(element, type, handle);
3476                 }
3477               }
3478
3479               eventFns.push(fn);
3480             };
3481
3482             while (i--) {
3483               type = types[i];
3484               if (MOUSE_EVENT_MAP[type]) {
3485                 addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
3486                 addHandler(type, undefined, true);
3487               } else {
3488                 addHandler(type);
3489               }
3490             }
3491           },
3492
3493           off: jqLiteOff,
3494
3495           one: function(element, type, fn) {
3496             element = jqLite(element);
3497
3498             //add the listener twice so that when it is called
3499             //you can remove the original function and still be
3500             //able to call element.off(ev, fn) normally
3501             element.on(type, function onFn() {
3502               element.off(type, fn);
3503               element.off(type, onFn);
3504             });
3505             element.on(type, fn);
3506           },
3507
3508           replaceWith: function(element, replaceNode) {
3509             var index, parent = element.parentNode;
3510             jqLiteDealoc(element);
3511             forEach(new JQLite(replaceNode), function(node) {
3512               if (index) {
3513                 parent.insertBefore(node, index.nextSibling);
3514               } else {
3515                 parent.replaceChild(node, element);
3516               }
3517               index = node;
3518             });
3519           },
3520
3521           children: function(element) {
3522             var children = [];
3523             forEach(element.childNodes, function(element) {
3524               if (element.nodeType === NODE_TYPE_ELEMENT) {
3525                 children.push(element);
3526               }
3527             });
3528             return children;
3529           },
3530
3531           contents: function(element) {
3532             return element.contentDocument || element.childNodes || [];
3533           },
3534
3535           append: function(element, node) {
3536             var nodeType = element.nodeType;
3537             if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3538
3539             node = new JQLite(node);
3540
3541             for (var i = 0, ii = node.length; i < ii; i++) {
3542               var child = node[i];
3543               element.appendChild(child);
3544             }
3545           },
3546
3547           prepend: function(element, node) {
3548             if (element.nodeType === NODE_TYPE_ELEMENT) {
3549               var index = element.firstChild;
3550               forEach(new JQLite(node), function(child) {
3551                 element.insertBefore(child, index);
3552               });
3553             }
3554           },
3555
3556           wrap: function(element, wrapNode) {
3557             wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3558             var parent = element.parentNode;
3559             if (parent) {
3560               parent.replaceChild(wrapNode, element);
3561             }
3562             wrapNode.appendChild(element);
3563           },
3564
3565           remove: jqLiteRemove,
3566
3567           detach: function(element) {
3568             jqLiteRemove(element, true);
3569           },
3570
3571           after: function(element, newElement) {
3572             var index = element, parent = element.parentNode;
3573             newElement = new JQLite(newElement);
3574
3575             for (var i = 0, ii = newElement.length; i < ii; i++) {
3576               var node = newElement[i];
3577               parent.insertBefore(node, index.nextSibling);
3578               index = node;
3579             }
3580           },
3581
3582           addClass: jqLiteAddClass,
3583           removeClass: jqLiteRemoveClass,
3584
3585           toggleClass: function(element, selector, condition) {
3586             if (selector) {
3587               forEach(selector.split(' '), function(className) {
3588                 var classCondition = condition;
3589                 if (isUndefined(classCondition)) {
3590                   classCondition = !jqLiteHasClass(element, className);
3591                 }
3592                 (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3593               });
3594             }
3595           },
3596
3597           parent: function(element) {
3598             var parent = element.parentNode;
3599             return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3600           },
3601
3602           next: function(element) {
3603             return element.nextElementSibling;
3604           },
3605
3606           find: function(element, selector) {
3607             if (element.getElementsByTagName) {
3608               return element.getElementsByTagName(selector);
3609             } else {
3610               return [];
3611             }
3612           },
3613
3614           clone: jqLiteClone,
3615
3616           triggerHandler: function(element, event, extraParameters) {
3617
3618             var dummyEvent, eventFnsCopy, handlerArgs;
3619             var eventName = event.type || event;
3620             var expandoStore = jqLiteExpandoStore(element);
3621             var events = expandoStore && expandoStore.events;
3622             var eventFns = events && events[eventName];
3623
3624             if (eventFns) {
3625               // Create a dummy event to pass to the handlers
3626               dummyEvent = {
3627                 preventDefault: function() { this.defaultPrevented = true; },
3628                 isDefaultPrevented: function() { return this.defaultPrevented === true; },
3629                 stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3630                 isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3631                 stopPropagation: noop,
3632                 type: eventName,
3633                 target: element
3634               };
3635
3636               // If a custom event was provided then extend our dummy event with it
3637               if (event.type) {
3638                 dummyEvent = extend(dummyEvent, event);
3639               }
3640
3641               // Copy event handlers in case event handlers array is modified during execution.
3642               eventFnsCopy = shallowCopy(eventFns);
3643               handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3644
3645               forEach(eventFnsCopy, function(fn) {
3646                 if (!dummyEvent.isImmediatePropagationStopped()) {
3647                   fn.apply(element, handlerArgs);
3648                 }
3649               });
3650             }
3651           }
3652         }, function(fn, name) {
3653           /**
3654            * chaining functions
3655            */
3656           JQLite.prototype[name] = function(arg1, arg2, arg3) {
3657             var value;
3658
3659             for (var i = 0, ii = this.length; i < ii; i++) {
3660               if (isUndefined(value)) {
3661                 value = fn(this[i], arg1, arg2, arg3);
3662                 if (isDefined(value)) {
3663                   // any function which returns a value needs to be wrapped
3664                   value = jqLite(value);
3665                 }
3666               } else {
3667                 jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3668               }
3669             }
3670             return isDefined(value) ? value : this;
3671           };
3672
3673           // bind legacy bind/unbind to on/off
3674           JQLite.prototype.bind = JQLite.prototype.on;
3675           JQLite.prototype.unbind = JQLite.prototype.off;
3676         });
3677
3678
3679         // Provider for private $$jqLite service
3680         function $$jqLiteProvider() {
3681           this.$get = function $$jqLite() {
3682             return extend(JQLite, {
3683               hasClass: function(node, classes) {
3684                 if (node.attr) node = node[0];
3685                 return jqLiteHasClass(node, classes);
3686               },
3687               addClass: function(node, classes) {
3688                 if (node.attr) node = node[0];
3689                 return jqLiteAddClass(node, classes);
3690               },
3691               removeClass: function(node, classes) {
3692                 if (node.attr) node = node[0];
3693                 return jqLiteRemoveClass(node, classes);
3694               }
3695             });
3696           };
3697         }
3698
3699         /**
3700          * Computes a hash of an 'obj'.
3701          * Hash of a:
3702          *  string is string
3703          *  number is number as string
3704          *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3705          *         that is also assigned to the $$hashKey property of the object.
3706          *
3707          * @param obj
3708          * @returns {string} hash string such that the same input will have the same hash string.
3709          *         The resulting string key is in 'type:hashKey' format.
3710          */
3711         function hashKey(obj, nextUidFn) {
3712           var key = obj && obj.$$hashKey;
3713
3714           if (key) {
3715             if (typeof key === 'function') {
3716               key = obj.$$hashKey();
3717             }
3718             return key;
3719           }
3720
3721           var objType = typeof obj;
3722           if (objType == 'function' || (objType == 'object' && obj !== null)) {
3723             key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3724           } else {
3725             key = objType + ':' + obj;
3726           }
3727
3728           return key;
3729         }
3730
3731         /**
3732          * HashMap which can use objects as keys
3733          */
3734         function HashMap(array, isolatedUid) {
3735           if (isolatedUid) {
3736             var uid = 0;
3737             this.nextUid = function() {
3738               return ++uid;
3739             };
3740           }
3741           forEach(array, this.put, this);
3742         }
3743         HashMap.prototype = {
3744           /**
3745            * Store key value pair
3746            * @param key key to store can be any type
3747            * @param value value to store can be any type
3748            */
3749           put: function(key, value) {
3750             this[hashKey(key, this.nextUid)] = value;
3751           },
3752
3753           /**
3754            * @param key
3755            * @returns {Object} the value for the key
3756            */
3757           get: function(key) {
3758             return this[hashKey(key, this.nextUid)];
3759           },
3760
3761           /**
3762            * Remove the key/value pair
3763            * @param key
3764            */
3765           remove: function(key) {
3766             var value = this[key = hashKey(key, this.nextUid)];
3767             delete this[key];
3768             return value;
3769           }
3770         };
3771
3772         var $$HashMapProvider = [function() {
3773           this.$get = [function() {
3774             return HashMap;
3775           }];
3776         }];
3777
3778         /**
3779          * @ngdoc function
3780          * @module ng
3781          * @name angular.injector
3782          * @kind function
3783          *
3784          * @description
3785          * Creates an injector object that can be used for retrieving services as well as for
3786          * dependency injection (see {@link guide/di dependency injection}).
3787          *
3788          * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3789          *     {@link angular.module}. The `ng` module must be explicitly added.
3790          * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3791          *     disallows argument name annotation inference.
3792          * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3793          *
3794          * @example
3795          * Typical usage
3796          * ```js
3797          *   // create an injector
3798          *   var $injector = angular.injector(['ng']);
3799          *
3800          *   // use the injector to kick off your application
3801          *   // use the type inference to auto inject arguments, or use implicit injection
3802          *   $injector.invoke(function($rootScope, $compile, $document) {
3803          *     $compile($document)($rootScope);
3804          *     $rootScope.$digest();
3805          *   });
3806          * ```
3807          *
3808          * Sometimes you want to get access to the injector of a currently running Angular app
3809          * from outside Angular. Perhaps, you want to inject and compile some markup after the
3810          * application has been bootstrapped. You can do this using the extra `injector()` added
3811          * to JQuery/jqLite elements. See {@link angular.element}.
3812          *
3813          * *This is fairly rare but could be the case if a third party library is injecting the
3814          * markup.*
3815          *
3816          * In the following example a new block of HTML containing a `ng-controller`
3817          * directive is added to the end of the document body by JQuery. We then compile and link
3818          * it into the current AngularJS scope.
3819          *
3820          * ```js
3821          * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3822          * $(document.body).append($div);
3823          *
3824          * angular.element(document).injector().invoke(function($compile) {
3825          *   var scope = angular.element($div).scope();
3826          *   $compile($div)(scope);
3827          * });
3828          * ```
3829          */
3830
3831
3832         /**
3833          * @ngdoc module
3834          * @name auto
3835          * @description
3836          *
3837          * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3838          */
3839
3840         var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
3841         var FN_ARG_SPLIT = /,/;
3842         var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3843         var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3844         var $injectorMinErr = minErr('$injector');
3845
3846         function anonFn(fn) {
3847           // For anonymous functions, showing at the very least the function signature can help in
3848           // debugging.
3849           var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3850               args = fnText.match(FN_ARGS);
3851           if (args) {
3852             return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3853           }
3854           return 'fn';
3855         }
3856
3857         function annotate(fn, strictDi, name) {
3858           var $inject,
3859               fnText,
3860               argDecl,
3861               last;
3862
3863           if (typeof fn === 'function') {
3864             if (!($inject = fn.$inject)) {
3865               $inject = [];
3866               if (fn.length) {
3867                 if (strictDi) {
3868                   if (!isString(name) || !name) {
3869                     name = fn.name || anonFn(fn);
3870                   }
3871                   throw $injectorMinErr('strictdi',
3872                     '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3873                 }
3874                 fnText = fn.toString().replace(STRIP_COMMENTS, '');
3875                 argDecl = fnText.match(FN_ARGS);
3876                 forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3877                   arg.replace(FN_ARG, function(all, underscore, name) {
3878                     $inject.push(name);
3879                   });
3880                 });
3881               }
3882               fn.$inject = $inject;
3883             }
3884           } else if (isArray(fn)) {
3885             last = fn.length - 1;
3886             assertArgFn(fn[last], 'fn');
3887             $inject = fn.slice(0, last);
3888           } else {
3889             assertArgFn(fn, 'fn', true);
3890           }
3891           return $inject;
3892         }
3893
3894         ///////////////////////////////////////
3895
3896         /**
3897          * @ngdoc service
3898          * @name $injector
3899          *
3900          * @description
3901          *
3902          * `$injector` is used to retrieve object instances as defined by
3903          * {@link auto.$provide provider}, instantiate types, invoke methods,
3904          * and load modules.
3905          *
3906          * The following always holds true:
3907          *
3908          * ```js
3909          *   var $injector = angular.injector();
3910          *   expect($injector.get('$injector')).toBe($injector);
3911          *   expect($injector.invoke(function($injector) {
3912          *     return $injector;
3913          *   })).toBe($injector);
3914          * ```
3915          *
3916          * # Injection Function Annotation
3917          *
3918          * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3919          * following are all valid ways of annotating function with injection arguments and are equivalent.
3920          *
3921          * ```js
3922          *   // inferred (only works if code not minified/obfuscated)
3923          *   $injector.invoke(function(serviceA){});
3924          *
3925          *   // annotated
3926          *   function explicit(serviceA) {};
3927          *   explicit.$inject = ['serviceA'];
3928          *   $injector.invoke(explicit);
3929          *
3930          *   // inline
3931          *   $injector.invoke(['serviceA', function(serviceA){}]);
3932          * ```
3933          *
3934          * ## Inference
3935          *
3936          * In JavaScript calling `toString()` on a function returns the function definition. The definition
3937          * can then be parsed and the function arguments can be extracted. This method of discovering
3938          * annotations is disallowed when the injector is in strict mode.
3939          * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3940          * argument names.
3941          *
3942          * ## `$inject` Annotation
3943          * By adding an `$inject` property onto a function the injection parameters can be specified.
3944          *
3945          * ## Inline
3946          * As an array of injection names, where the last item in the array is the function to call.
3947          */
3948
3949         /**
3950          * @ngdoc method
3951          * @name $injector#get
3952          *
3953          * @description
3954          * Return an instance of the service.
3955          *
3956          * @param {string} name The name of the instance to retrieve.
3957          * @param {string=} caller An optional string to provide the origin of the function call for error messages.
3958          * @return {*} The instance.
3959          */
3960
3961         /**
3962          * @ngdoc method
3963          * @name $injector#invoke
3964          *
3965          * @description
3966          * Invoke the method and supply the method arguments from the `$injector`.
3967          *
3968          * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
3969          *   injected according to the {@link guide/di $inject Annotation} rules.
3970          * @param {Object=} self The `this` for the invoked method.
3971          * @param {Object=} locals Optional object. If preset then any argument names are read from this
3972          *                         object first, before the `$injector` is consulted.
3973          * @returns {*} the value returned by the invoked `fn` function.
3974          */
3975
3976         /**
3977          * @ngdoc method
3978          * @name $injector#has
3979          *
3980          * @description
3981          * Allows the user to query if the particular service exists.
3982          *
3983          * @param {string} name Name of the service to query.
3984          * @returns {boolean} `true` if injector has given service.
3985          */
3986
3987         /**
3988          * @ngdoc method
3989          * @name $injector#instantiate
3990          * @description
3991          * Create a new instance of JS type. The method takes a constructor function, invokes the new
3992          * operator, and supplies all of the arguments to the constructor function as specified by the
3993          * constructor annotation.
3994          *
3995          * @param {Function} Type Annotated constructor function.
3996          * @param {Object=} locals Optional object. If preset then any argument names are read from this
3997          * object first, before the `$injector` is consulted.
3998          * @returns {Object} new instance of `Type`.
3999          */
4000
4001         /**
4002          * @ngdoc method
4003          * @name $injector#annotate
4004          *
4005          * @description
4006          * Returns an array of service names which the function is requesting for injection. This API is
4007          * used by the injector to determine which services need to be injected into the function when the
4008          * function is invoked. There are three ways in which the function can be annotated with the needed
4009          * dependencies.
4010          *
4011          * # Argument names
4012          *
4013          * The simplest form is to extract the dependencies from the arguments of the function. This is done
4014          * by converting the function into a string using `toString()` method and extracting the argument
4015          * names.
4016          * ```js
4017          *   // Given
4018          *   function MyController($scope, $route) {
4019          *     // ...
4020          *   }
4021          *
4022          *   // Then
4023          *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4024          * ```
4025          *
4026          * You can disallow this method by using strict injection mode.
4027          *
4028          * This method does not work with code minification / obfuscation. For this reason the following
4029          * annotation strategies are supported.
4030          *
4031          * # The `$inject` property
4032          *
4033          * If a function has an `$inject` property and its value is an array of strings, then the strings
4034          * represent names of services to be injected into the function.
4035          * ```js
4036          *   // Given
4037          *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
4038          *     // ...
4039          *   }
4040          *   // Define function dependencies
4041          *   MyController['$inject'] = ['$scope', '$route'];
4042          *
4043          *   // Then
4044          *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4045          * ```
4046          *
4047          * # The array notation
4048          *
4049          * It is often desirable to inline Injected functions and that's when setting the `$inject` property
4050          * is very inconvenient. In these situations using the array notation to specify the dependencies in
4051          * a way that survives minification is a better choice:
4052          *
4053          * ```js
4054          *   // We wish to write this (not minification / obfuscation safe)
4055          *   injector.invoke(function($compile, $rootScope) {
4056          *     // ...
4057          *   });
4058          *
4059          *   // We are forced to write break inlining
4060          *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
4061          *     // ...
4062          *   };
4063          *   tmpFn.$inject = ['$compile', '$rootScope'];
4064          *   injector.invoke(tmpFn);
4065          *
4066          *   // To better support inline function the inline annotation is supported
4067          *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
4068          *     // ...
4069          *   }]);
4070          *
4071          *   // Therefore
4072          *   expect(injector.annotate(
4073          *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
4074          *    ).toEqual(['$compile', '$rootScope']);
4075          * ```
4076          *
4077          * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
4078          * be retrieved as described above.
4079          *
4080          * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
4081          *
4082          * @returns {Array.<string>} The names of the services which the function requires.
4083          */
4084
4085
4086
4087
4088         /**
4089          * @ngdoc service
4090          * @name $provide
4091          *
4092          * @description
4093          *
4094          * The {@link auto.$provide $provide} service has a number of methods for registering components
4095          * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
4096          * {@link angular.Module}.
4097          *
4098          * An Angular **service** is a singleton object created by a **service factory**.  These **service
4099          * factories** are functions which, in turn, are created by a **service provider**.
4100          * The **service providers** are constructor functions. When instantiated they must contain a
4101          * property called `$get`, which holds the **service factory** function.
4102          *
4103          * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
4104          * correct **service provider**, instantiating it and then calling its `$get` **service factory**
4105          * function to get the instance of the **service**.
4106          *
4107          * Often services have no configuration options and there is no need to add methods to the service
4108          * provider.  The provider will be no more than a constructor function with a `$get` property. For
4109          * these cases the {@link auto.$provide $provide} service has additional helper methods to register
4110          * services without specifying a provider.
4111          *
4112          * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
4113          *     {@link auto.$injector $injector}
4114          * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
4115          *     providers and services.
4116          * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
4117          *     services, not providers.
4118          * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
4119          *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
4120          *     given factory function.
4121          * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
4122          *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
4123          *      a new object using the given constructor function.
4124          *
4125          * See the individual methods for more information and examples.
4126          */
4127
4128         /**
4129          * @ngdoc method
4130          * @name $provide#provider
4131          * @description
4132          *
4133          * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
4134          * are constructor functions, whose instances are responsible for "providing" a factory for a
4135          * service.
4136          *
4137          * Service provider names start with the name of the service they provide followed by `Provider`.
4138          * For example, the {@link ng.$log $log} service has a provider called
4139          * {@link ng.$logProvider $logProvider}.
4140          *
4141          * Service provider objects can have additional methods which allow configuration of the provider
4142          * and its service. Importantly, you can configure what kind of service is created by the `$get`
4143          * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
4144          * method {@link ng.$logProvider#debugEnabled debugEnabled}
4145          * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
4146          * console or not.
4147          *
4148          * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
4149                                 'Provider'` key.
4150          * @param {(Object|function())} provider If the provider is:
4151          *
4152          *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
4153          *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
4154          *   - `Constructor`: a new instance of the provider will be created using
4155          *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
4156          *
4157          * @returns {Object} registered provider instance
4158
4159          * @example
4160          *
4161          * The following example shows how to create a simple event tracking service and register it using
4162          * {@link auto.$provide#provider $provide.provider()}.
4163          *
4164          * ```js
4165          *  // Define the eventTracker provider
4166          *  function EventTrackerProvider() {
4167          *    var trackingUrl = '/track';
4168          *
4169          *    // A provider method for configuring where the tracked events should been saved
4170          *    this.setTrackingUrl = function(url) {
4171          *      trackingUrl = url;
4172          *    };
4173          *
4174          *    // The service factory function
4175          *    this.$get = ['$http', function($http) {
4176          *      var trackedEvents = {};
4177          *      return {
4178          *        // Call this to track an event
4179          *        event: function(event) {
4180          *          var count = trackedEvents[event] || 0;
4181          *          count += 1;
4182          *          trackedEvents[event] = count;
4183          *          return count;
4184          *        },
4185          *        // Call this to save the tracked events to the trackingUrl
4186          *        save: function() {
4187          *          $http.post(trackingUrl, trackedEvents);
4188          *        }
4189          *      };
4190          *    }];
4191          *  }
4192          *
4193          *  describe('eventTracker', function() {
4194          *    var postSpy;
4195          *
4196          *    beforeEach(module(function($provide) {
4197          *      // Register the eventTracker provider
4198          *      $provide.provider('eventTracker', EventTrackerProvider);
4199          *    }));
4200          *
4201          *    beforeEach(module(function(eventTrackerProvider) {
4202          *      // Configure eventTracker provider
4203          *      eventTrackerProvider.setTrackingUrl('/custom-track');
4204          *    }));
4205          *
4206          *    it('tracks events', inject(function(eventTracker) {
4207          *      expect(eventTracker.event('login')).toEqual(1);
4208          *      expect(eventTracker.event('login')).toEqual(2);
4209          *    }));
4210          *
4211          *    it('saves to the tracking url', inject(function(eventTracker, $http) {
4212          *      postSpy = spyOn($http, 'post');
4213          *      eventTracker.event('login');
4214          *      eventTracker.save();
4215          *      expect(postSpy).toHaveBeenCalled();
4216          *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
4217          *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
4218          *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
4219          *    }));
4220          *  });
4221          * ```
4222          */
4223
4224         /**
4225          * @ngdoc method
4226          * @name $provide#factory
4227          * @description
4228          *
4229          * Register a **service factory**, which will be called to return the service instance.
4230          * This is short for registering a service where its provider consists of only a `$get` property,
4231          * which is the given service factory function.
4232          * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
4233          * configure your service in a provider.
4234          *
4235          * @param {string} name The name of the instance.
4236          * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
4237          *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
4238          * @returns {Object} registered provider instance
4239          *
4240          * @example
4241          * Here is an example of registering a service
4242          * ```js
4243          *   $provide.factory('ping', ['$http', function($http) {
4244          *     return function ping() {
4245          *       return $http.send('/ping');
4246          *     };
4247          *   }]);
4248          * ```
4249          * You would then inject and use this service like this:
4250          * ```js
4251          *   someModule.controller('Ctrl', ['ping', function(ping) {
4252          *     ping();
4253          *   }]);
4254          * ```
4255          */
4256
4257
4258         /**
4259          * @ngdoc method
4260          * @name $provide#service
4261          * @description
4262          *
4263          * Register a **service constructor**, which will be invoked with `new` to create the service
4264          * instance.
4265          * This is short for registering a service where its provider's `$get` property is the service
4266          * constructor function that will be used to instantiate the service instance.
4267          *
4268          * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4269          * as a type/class.
4270          *
4271          * @param {string} name The name of the instance.
4272          * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
4273          *     that will be instantiated.
4274          * @returns {Object} registered provider instance
4275          *
4276          * @example
4277          * Here is an example of registering a service using
4278          * {@link auto.$provide#service $provide.service(class)}.
4279          * ```js
4280          *   var Ping = function($http) {
4281          *     this.$http = $http;
4282          *   };
4283          *
4284          *   Ping.$inject = ['$http'];
4285          *
4286          *   Ping.prototype.send = function() {
4287          *     return this.$http.get('/ping');
4288          *   };
4289          *   $provide.service('ping', Ping);
4290          * ```
4291          * You would then inject and use this service like this:
4292          * ```js
4293          *   someModule.controller('Ctrl', ['ping', function(ping) {
4294          *     ping.send();
4295          *   }]);
4296          * ```
4297          */
4298
4299
4300         /**
4301          * @ngdoc method
4302          * @name $provide#value
4303          * @description
4304          *
4305          * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4306          * number, an array, an object or a function.  This is short for registering a service where its
4307          * provider's `$get` property is a factory function that takes no arguments and returns the **value
4308          * service**.
4309          *
4310          * Value services are similar to constant services, except that they cannot be injected into a
4311          * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4312          * an Angular
4313          * {@link auto.$provide#decorator decorator}.
4314          *
4315          * @param {string} name The name of the instance.
4316          * @param {*} value The value.
4317          * @returns {Object} registered provider instance
4318          *
4319          * @example
4320          * Here are some examples of creating value services.
4321          * ```js
4322          *   $provide.value('ADMIN_USER', 'admin');
4323          *
4324          *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
4325          *
4326          *   $provide.value('halfOf', function(value) {
4327          *     return value / 2;
4328          *   });
4329          * ```
4330          */
4331
4332
4333         /**
4334          * @ngdoc method
4335          * @name $provide#constant
4336          * @description
4337          *
4338          * Register a **constant service**, such as a string, a number, an array, an object or a function,
4339          * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
4340          * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4341          * be overridden by an Angular {@link auto.$provide#decorator decorator}.
4342          *
4343          * @param {string} name The name of the constant.
4344          * @param {*} value The constant value.
4345          * @returns {Object} registered instance
4346          *
4347          * @example
4348          * Here a some examples of creating constants:
4349          * ```js
4350          *   $provide.constant('SHARD_HEIGHT', 306);
4351          *
4352          *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
4353          *
4354          *   $provide.constant('double', function(value) {
4355          *     return value * 2;
4356          *   });
4357          * ```
4358          */
4359
4360
4361         /**
4362          * @ngdoc method
4363          * @name $provide#decorator
4364          * @description
4365          *
4366          * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
4367          * intercepts the creation of a service, allowing it to override or modify the behaviour of the
4368          * service. The object returned by the decorator may be the original service, or a new service
4369          * object which replaces or wraps and delegates to the original service.
4370          *
4371          * @param {string} name The name of the service to decorate.
4372          * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
4373          *    instantiated and should return the decorated service instance. The function is called using
4374          *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
4375          *    Local injection arguments:
4376          *
4377          *    * `$delegate` - The original service instance, which can be monkey patched, configured,
4378          *      decorated or delegated to.
4379          *
4380          * @example
4381          * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4382          * calls to {@link ng.$log#error $log.warn()}.
4383          * ```js
4384          *   $provide.decorator('$log', ['$delegate', function($delegate) {
4385          *     $delegate.warn = $delegate.error;
4386          *     return $delegate;
4387          *   }]);
4388          * ```
4389          */
4390
4391
4392         function createInjector(modulesToLoad, strictDi) {
4393           strictDi = (strictDi === true);
4394           var INSTANTIATING = {},
4395               providerSuffix = 'Provider',
4396               path = [],
4397               loadedModules = new HashMap([], true),
4398               providerCache = {
4399                 $provide: {
4400                     provider: supportObject(provider),
4401                     factory: supportObject(factory),
4402                     service: supportObject(service),
4403                     value: supportObject(value),
4404                     constant: supportObject(constant),
4405                     decorator: decorator
4406                   }
4407               },
4408               providerInjector = (providerCache.$injector =
4409                   createInternalInjector(providerCache, function(serviceName, caller) {
4410                     if (angular.isString(caller)) {
4411                       path.push(caller);
4412                     }
4413                     throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4414                   })),
4415               instanceCache = {},
4416               instanceInjector = (instanceCache.$injector =
4417                   createInternalInjector(instanceCache, function(serviceName, caller) {
4418                     var provider = providerInjector.get(serviceName + providerSuffix, caller);
4419                     return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4420                   }));
4421
4422
4423           forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
4424
4425           return instanceInjector;
4426
4427           ////////////////////////////////////
4428           // $provider
4429           ////////////////////////////////////
4430
4431           function supportObject(delegate) {
4432             return function(key, value) {
4433               if (isObject(key)) {
4434                 forEach(key, reverseParams(delegate));
4435               } else {
4436                 return delegate(key, value);
4437               }
4438             };
4439           }
4440
4441           function provider(name, provider_) {
4442             assertNotHasOwnProperty(name, 'service');
4443             if (isFunction(provider_) || isArray(provider_)) {
4444               provider_ = providerInjector.instantiate(provider_);
4445             }
4446             if (!provider_.$get) {
4447               throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4448             }
4449             return providerCache[name + providerSuffix] = provider_;
4450           }
4451
4452           function enforceReturnValue(name, factory) {
4453             return function enforcedReturnValue() {
4454               var result = instanceInjector.invoke(factory, this);
4455               if (isUndefined(result)) {
4456                 throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4457               }
4458               return result;
4459             };
4460           }
4461
4462           function factory(name, factoryFn, enforce) {
4463             return provider(name, {
4464               $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4465             });
4466           }
4467
4468           function service(name, constructor) {
4469             return factory(name, ['$injector', function($injector) {
4470               return $injector.instantiate(constructor);
4471             }]);
4472           }
4473
4474           function value(name, val) { return factory(name, valueFn(val), false); }
4475
4476           function constant(name, value) {
4477             assertNotHasOwnProperty(name, 'constant');
4478             providerCache[name] = value;
4479             instanceCache[name] = value;
4480           }
4481
4482           function decorator(serviceName, decorFn) {
4483             var origProvider = providerInjector.get(serviceName + providerSuffix),
4484                 orig$get = origProvider.$get;
4485
4486             origProvider.$get = function() {
4487               var origInstance = instanceInjector.invoke(orig$get, origProvider);
4488               return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4489             };
4490           }
4491
4492           ////////////////////////////////////
4493           // Module Loading
4494           ////////////////////////////////////
4495           function loadModules(modulesToLoad) {
4496             assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
4497             var runBlocks = [], moduleFn;
4498             forEach(modulesToLoad, function(module) {
4499               if (loadedModules.get(module)) return;
4500               loadedModules.put(module, true);
4501
4502               function runInvokeQueue(queue) {
4503                 var i, ii;
4504                 for (i = 0, ii = queue.length; i < ii; i++) {
4505                   var invokeArgs = queue[i],
4506                       provider = providerInjector.get(invokeArgs[0]);
4507
4508                   provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4509                 }
4510               }
4511
4512               try {
4513                 if (isString(module)) {
4514                   moduleFn = angularModule(module);
4515                   runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4516                   runInvokeQueue(moduleFn._invokeQueue);
4517                   runInvokeQueue(moduleFn._configBlocks);
4518                 } else if (isFunction(module)) {
4519                     runBlocks.push(providerInjector.invoke(module));
4520                 } else if (isArray(module)) {
4521                     runBlocks.push(providerInjector.invoke(module));
4522                 } else {
4523                   assertArgFn(module, 'module');
4524                 }
4525               } catch (e) {
4526                 if (isArray(module)) {
4527                   module = module[module.length - 1];
4528                 }
4529                 if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4530                   // Safari & FF's stack traces don't contain error.message content
4531                   // unlike those of Chrome and IE
4532                   // So if stack doesn't contain message, we create a new string that contains both.
4533                   // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4534                   /* jshint -W022 */
4535                   e = e.message + '\n' + e.stack;
4536                 }
4537                 throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4538                           module, e.stack || e.message || e);
4539               }
4540             });
4541             return runBlocks;
4542           }
4543
4544           ////////////////////////////////////
4545           // internal Injector
4546           ////////////////////////////////////
4547
4548           function createInternalInjector(cache, factory) {
4549
4550             function getService(serviceName, caller) {
4551               if (cache.hasOwnProperty(serviceName)) {
4552                 if (cache[serviceName] === INSTANTIATING) {
4553                   throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4554                             serviceName + ' <- ' + path.join(' <- '));
4555                 }
4556                 return cache[serviceName];
4557               } else {
4558                 try {
4559                   path.unshift(serviceName);
4560                   cache[serviceName] = INSTANTIATING;
4561                   return cache[serviceName] = factory(serviceName, caller);
4562                 } catch (err) {
4563                   if (cache[serviceName] === INSTANTIATING) {
4564                     delete cache[serviceName];
4565                   }
4566                   throw err;
4567                 } finally {
4568                   path.shift();
4569                 }
4570               }
4571             }
4572
4573             function invoke(fn, self, locals, serviceName) {
4574               if (typeof locals === 'string') {
4575                 serviceName = locals;
4576                 locals = null;
4577               }
4578
4579               var args = [],
4580                   $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4581                   length, i,
4582                   key;
4583
4584               for (i = 0, length = $inject.length; i < length; i++) {
4585                 key = $inject[i];
4586                 if (typeof key !== 'string') {
4587                   throw $injectorMinErr('itkn',
4588                           'Incorrect injection token! Expected service name as string, got {0}', key);
4589                 }
4590                 args.push(
4591                   locals && locals.hasOwnProperty(key)
4592                   ? locals[key]
4593                   : getService(key, serviceName)
4594                 );
4595               }
4596               if (isArray(fn)) {
4597                 fn = fn[length];
4598               }
4599
4600               // http://jsperf.com/angularjs-invoke-apply-vs-switch
4601               // #5388
4602               return fn.apply(self, args);
4603             }
4604
4605             function instantiate(Type, locals, serviceName) {
4606               // Check if Type is annotated and use just the given function at n-1 as parameter
4607               // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4608               // Object creation: http://jsperf.com/create-constructor/2
4609               var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4610               var returnedValue = invoke(Type, instance, locals, serviceName);
4611
4612               return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4613             }
4614
4615             return {
4616               invoke: invoke,
4617               instantiate: instantiate,
4618               get: getService,
4619               annotate: createInjector.$$annotate,
4620               has: function(name) {
4621                 return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4622               }
4623             };
4624           }
4625         }
4626
4627         createInjector.$$annotate = annotate;
4628
4629         /**
4630          * @ngdoc provider
4631          * @name $anchorScrollProvider
4632          *
4633          * @description
4634          * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4635          * {@link ng.$location#hash $location.hash()} changes.
4636          */
4637         function $AnchorScrollProvider() {
4638
4639           var autoScrollingEnabled = true;
4640
4641           /**
4642            * @ngdoc method
4643            * @name $anchorScrollProvider#disableAutoScrolling
4644            *
4645            * @description
4646            * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4647            * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4648            * Use this method to disable automatic scrolling.
4649            *
4650            * If automatic scrolling is disabled, one must explicitly call
4651            * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4652            * current hash.
4653            */
4654           this.disableAutoScrolling = function() {
4655             autoScrollingEnabled = false;
4656           };
4657
4658           /**
4659            * @ngdoc service
4660            * @name $anchorScroll
4661            * @kind function
4662            * @requires $window
4663            * @requires $location
4664            * @requires $rootScope
4665            *
4666            * @description
4667            * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
4668            * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
4669            * in the
4670            * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
4671            *
4672            * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4673            * match any anchor whenever it changes. This can be disabled by calling
4674            * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4675            *
4676            * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4677            * vertical scroll-offset (either fixed or dynamic).
4678            *
4679            * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
4680            *                       {@link ng.$location#hash $location.hash()} will be used.
4681            *
4682            * @property {(number|function|jqLite)} yOffset
4683            * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4684            * positioned elements at the top of the page, such as navbars, headers etc.
4685            *
4686            * `yOffset` can be specified in various ways:
4687            * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4688            * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4689            *   a number representing the offset (in pixels).<br /><br />
4690            * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4691            *   the top of the page to the element's bottom will be used as offset.<br />
4692            *   **Note**: The element will be taken into account only as long as its `position` is set to
4693            *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4694            *   their height and/or positioning according to the viewport's size.
4695            *
4696            * <br />
4697            * <div class="alert alert-warning">
4698            * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4699            * not some child element.
4700            * </div>
4701            *
4702            * @example
4703              <example module="anchorScrollExample">
4704                <file name="index.html">
4705                  <div id="scrollArea" ng-controller="ScrollController">
4706                    <a ng-click="gotoBottom()">Go to bottom</a>
4707                    <a id="bottom"></a> You're at the bottom!
4708                  </div>
4709                </file>
4710                <file name="script.js">
4711                  angular.module('anchorScrollExample', [])
4712                    .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4713                      function ($scope, $location, $anchorScroll) {
4714                        $scope.gotoBottom = function() {
4715                          // set the location.hash to the id of
4716                          // the element you wish to scroll to.
4717                          $location.hash('bottom');
4718
4719                          // call $anchorScroll()
4720                          $anchorScroll();
4721                        };
4722                      }]);
4723                </file>
4724                <file name="style.css">
4725                  #scrollArea {
4726                    height: 280px;
4727                    overflow: auto;
4728                  }
4729
4730                  #bottom {
4731                    display: block;
4732                    margin-top: 2000px;
4733                  }
4734                </file>
4735              </example>
4736            *
4737            * <hr />
4738            * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4739            * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4740            *
4741            * @example
4742              <example module="anchorScrollOffsetExample">
4743                <file name="index.html">
4744                  <div class="fixed-header" ng-controller="headerCtrl">
4745                    <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4746                      Go to anchor {{x}}
4747                    </a>
4748                  </div>
4749                  <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4750                    Anchor {{x}} of 5
4751                  </div>
4752                </file>
4753                <file name="script.js">
4754                  angular.module('anchorScrollOffsetExample', [])
4755                    .run(['$anchorScroll', function($anchorScroll) {
4756                      $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4757                    }])
4758                    .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4759                      function ($anchorScroll, $location, $scope) {
4760                        $scope.gotoAnchor = function(x) {
4761                          var newHash = 'anchor' + x;
4762                          if ($location.hash() !== newHash) {
4763                            // set the $location.hash to `newHash` and
4764                            // $anchorScroll will automatically scroll to it
4765                            $location.hash('anchor' + x);
4766                          } else {
4767                            // call $anchorScroll() explicitly,
4768                            // since $location.hash hasn't changed
4769                            $anchorScroll();
4770                          }
4771                        };
4772                      }
4773                    ]);
4774                </file>
4775                <file name="style.css">
4776                  body {
4777                    padding-top: 50px;
4778                  }
4779
4780                  .anchor {
4781                    border: 2px dashed DarkOrchid;
4782                    padding: 10px 10px 200px 10px;
4783                  }
4784
4785                  .fixed-header {
4786                    background-color: rgba(0, 0, 0, 0.2);
4787                    height: 50px;
4788                    position: fixed;
4789                    top: 0; left: 0; right: 0;
4790                  }
4791
4792                  .fixed-header > a {
4793                    display: inline-block;
4794                    margin: 5px 15px;
4795                  }
4796                </file>
4797              </example>
4798            */
4799           this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4800             var document = $window.document;
4801
4802             // Helper function to get first anchor from a NodeList
4803             // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4804             //  and working in all supported browsers.)
4805             function getFirstAnchor(list) {
4806               var result = null;
4807               Array.prototype.some.call(list, function(element) {
4808                 if (nodeName_(element) === 'a') {
4809                   result = element;
4810                   return true;
4811                 }
4812               });
4813               return result;
4814             }
4815
4816             function getYOffset() {
4817
4818               var offset = scroll.yOffset;
4819
4820               if (isFunction(offset)) {
4821                 offset = offset();
4822               } else if (isElement(offset)) {
4823                 var elem = offset[0];
4824                 var style = $window.getComputedStyle(elem);
4825                 if (style.position !== 'fixed') {
4826                   offset = 0;
4827                 } else {
4828                   offset = elem.getBoundingClientRect().bottom;
4829                 }
4830               } else if (!isNumber(offset)) {
4831                 offset = 0;
4832               }
4833
4834               return offset;
4835             }
4836
4837             function scrollTo(elem) {
4838               if (elem) {
4839                 elem.scrollIntoView();
4840
4841                 var offset = getYOffset();
4842
4843                 if (offset) {
4844                   // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4845                   // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4846                   // top of the viewport.
4847                   //
4848                   // IF the number of pixels from the top of `elem` to the end of the page's content is less
4849                   // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4850                   // way down the page.
4851                   //
4852                   // This is often the case for elements near the bottom of the page.
4853                   //
4854                   // In such cases we do not need to scroll the whole `offset` up, just the difference between
4855                   // the top of the element and the offset, which is enough to align the top of `elem` at the
4856                   // desired position.
4857                   var elemTop = elem.getBoundingClientRect().top;
4858                   $window.scrollBy(0, elemTop - offset);
4859                 }
4860               } else {
4861                 $window.scrollTo(0, 0);
4862               }
4863             }
4864
4865             function scroll(hash) {
4866               hash = isString(hash) ? hash : $location.hash();
4867               var elm;
4868
4869               // empty hash, scroll to the top of the page
4870               if (!hash) scrollTo(null);
4871
4872               // element with given id
4873               else if ((elm = document.getElementById(hash))) scrollTo(elm);
4874
4875               // first anchor with given name :-D
4876               else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4877
4878               // no element and hash == 'top', scroll to the top of the page
4879               else if (hash === 'top') scrollTo(null);
4880             }
4881
4882             // does not scroll when user clicks on anchor link that is currently on
4883             // (no url change, no $location.hash() change), browser native does scroll
4884             if (autoScrollingEnabled) {
4885               $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4886                 function autoScrollWatchAction(newVal, oldVal) {
4887                   // skip the initial scroll if $location.hash is empty
4888                   if (newVal === oldVal && newVal === '') return;
4889
4890                   jqLiteDocumentLoaded(function() {
4891                     $rootScope.$evalAsync(scroll);
4892                   });
4893                 });
4894             }
4895
4896             return scroll;
4897           }];
4898         }
4899
4900         var $animateMinErr = minErr('$animate');
4901         var ELEMENT_NODE = 1;
4902         var NG_ANIMATE_CLASSNAME = 'ng-animate';
4903
4904         function mergeClasses(a,b) {
4905           if (!a && !b) return '';
4906           if (!a) return b;
4907           if (!b) return a;
4908           if (isArray(a)) a = a.join(' ');
4909           if (isArray(b)) b = b.join(' ');
4910           return a + ' ' + b;
4911         }
4912
4913         function extractElementNode(element) {
4914           for (var i = 0; i < element.length; i++) {
4915             var elm = element[i];
4916             if (elm.nodeType === ELEMENT_NODE) {
4917               return elm;
4918             }
4919           }
4920         }
4921
4922         function splitClasses(classes) {
4923           if (isString(classes)) {
4924             classes = classes.split(' ');
4925           }
4926
4927           // Use createMap() to prevent class assumptions involving property names in
4928           // Object.prototype
4929           var obj = createMap();
4930           forEach(classes, function(klass) {
4931             // sometimes the split leaves empty string values
4932             // incase extra spaces were applied to the options
4933             if (klass.length) {
4934               obj[klass] = true;
4935             }
4936           });
4937           return obj;
4938         }
4939
4940         // if any other type of options value besides an Object value is
4941         // passed into the $animate.method() animation then this helper code
4942         // will be run which will ignore it. While this patch is not the
4943         // greatest solution to this, a lot of existing plugins depend on
4944         // $animate to either call the callback (< 1.2) or return a promise
4945         // that can be changed. This helper function ensures that the options
4946         // are wiped clean incase a callback function is provided.
4947         function prepareAnimateOptions(options) {
4948           return isObject(options)
4949               ? options
4950               : {};
4951         }
4952
4953         var $$CoreAnimateRunnerProvider = function() {
4954           this.$get = ['$q', '$$rAF', function($q, $$rAF) {
4955             function AnimateRunner() {}
4956             AnimateRunner.all = noop;
4957             AnimateRunner.chain = noop;
4958             AnimateRunner.prototype = {
4959               end: noop,
4960               cancel: noop,
4961               resume: noop,
4962               pause: noop,
4963               complete: noop,
4964               then: function(pass, fail) {
4965                 return $q(function(resolve) {
4966                   $$rAF(function() {
4967                     resolve();
4968                   });
4969                 }).then(pass, fail);
4970               }
4971             };
4972             return AnimateRunner;
4973           }];
4974         };
4975
4976         // this is prefixed with Core since it conflicts with
4977         // the animateQueueProvider defined in ngAnimate/animateQueue.js
4978         var $$CoreAnimateQueueProvider = function() {
4979           var postDigestQueue = new HashMap();
4980           var postDigestElements = [];
4981
4982           this.$get = ['$$AnimateRunner', '$rootScope',
4983                function($$AnimateRunner,   $rootScope) {
4984             return {
4985               enabled: noop,
4986               on: noop,
4987               off: noop,
4988               pin: noop,
4989
4990               push: function(element, event, options, domOperation) {
4991                 domOperation        && domOperation();
4992
4993                 options = options || {};
4994                 options.from        && element.css(options.from);
4995                 options.to          && element.css(options.to);
4996
4997                 if (options.addClass || options.removeClass) {
4998                   addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
4999                 }
5000
5001                 return new $$AnimateRunner(); // jshint ignore:line
5002               }
5003             };
5004
5005
5006             function updateData(data, classes, value) {
5007               var changed = false;
5008               if (classes) {
5009                 classes = isString(classes) ? classes.split(' ') :
5010                           isArray(classes) ? classes : [];
5011                 forEach(classes, function(className) {
5012                   if (className) {
5013                     changed = true;
5014                     data[className] = value;
5015                   }
5016                 });
5017               }
5018               return changed;
5019             }
5020
5021             function handleCSSClassChanges() {
5022               forEach(postDigestElements, function(element) {
5023                 var data = postDigestQueue.get(element);
5024                 if (data) {
5025                   var existing = splitClasses(element.attr('class'));
5026                   var toAdd = '';
5027                   var toRemove = '';
5028                   forEach(data, function(status, className) {
5029                     var hasClass = !!existing[className];
5030                     if (status !== hasClass) {
5031                       if (status) {
5032                         toAdd += (toAdd.length ? ' ' : '') + className;
5033                       } else {
5034                         toRemove += (toRemove.length ? ' ' : '') + className;
5035                       }
5036                     }
5037                   });
5038
5039                   forEach(element, function(elm) {
5040                     toAdd    && jqLiteAddClass(elm, toAdd);
5041                     toRemove && jqLiteRemoveClass(elm, toRemove);
5042                   });
5043                   postDigestQueue.remove(element);
5044                 }
5045               });
5046               postDigestElements.length = 0;
5047             }
5048
5049
5050             function addRemoveClassesPostDigest(element, add, remove) {
5051               var data = postDigestQueue.get(element) || {};
5052
5053               var classesAdded = updateData(data, add, true);
5054               var classesRemoved = updateData(data, remove, false);
5055
5056               if (classesAdded || classesRemoved) {
5057
5058                 postDigestQueue.put(element, data);
5059                 postDigestElements.push(element);
5060
5061                 if (postDigestElements.length === 1) {
5062                   $rootScope.$$postDigest(handleCSSClassChanges);
5063                 }
5064               }
5065             }
5066           }];
5067         };
5068
5069         /**
5070          * @ngdoc provider
5071          * @name $animateProvider
5072          *
5073          * @description
5074          * Default implementation of $animate that doesn't perform any animations, instead just
5075          * synchronously performs DOM updates and resolves the returned runner promise.
5076          *
5077          * In order to enable animations the `ngAnimate` module has to be loaded.
5078          *
5079          * To see the functional implementation check out `src/ngAnimate/animate.js`.
5080          */
5081         var $AnimateProvider = ['$provide', function($provide) {
5082           var provider = this;
5083
5084           this.$$registeredAnimations = Object.create(null);
5085
5086            /**
5087            * @ngdoc method
5088            * @name $animateProvider#register
5089            *
5090            * @description
5091            * Registers a new injectable animation factory function. The factory function produces the
5092            * animation object which contains callback functions for each event that is expected to be
5093            * animated.
5094            *
5095            *   * `eventFn`: `function(element, ... , doneFunction, options)`
5096            *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
5097            *   on the type of animation additional arguments will be injected into the animation function. The
5098            *   list below explains the function signatures for the different animation methods:
5099            *
5100            *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
5101            *   - addClass: function(element, addedClasses, doneFunction, options)
5102            *   - removeClass: function(element, removedClasses, doneFunction, options)
5103            *   - enter, leave, move: function(element, doneFunction, options)
5104            *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
5105            *
5106            *   Make sure to trigger the `doneFunction` once the animation is fully complete.
5107            *
5108            * ```js
5109            *   return {
5110            *     //enter, leave, move signature
5111            *     eventFn : function(element, done, options) {
5112            *       //code to run the animation
5113            *       //once complete, then run done()
5114            *       return function endFunction(wasCancelled) {
5115            *         //code to cancel the animation
5116            *       }
5117            *     }
5118            *   }
5119            * ```
5120            *
5121            * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
5122            * @param {Function} factory The factory function that will be executed to return the animation
5123            *                           object.
5124            */
5125           this.register = function(name, factory) {
5126             if (name && name.charAt(0) !== '.') {
5127               throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
5128             }
5129
5130             var key = name + '-animation';
5131             provider.$$registeredAnimations[name.substr(1)] = key;
5132             $provide.factory(key, factory);
5133           };
5134
5135           /**
5136            * @ngdoc method
5137            * @name $animateProvider#classNameFilter
5138            *
5139            * @description
5140            * Sets and/or returns the CSS class regular expression that is checked when performing
5141            * an animation. Upon bootstrap the classNameFilter value is not set at all and will
5142            * therefore enable $animate to attempt to perform an animation on any element that is triggered.
5143            * When setting the `classNameFilter` value, animations will only be performed on elements
5144            * that successfully match the filter expression. This in turn can boost performance
5145            * for low-powered devices as well as applications containing a lot of structural operations.
5146            * @param {RegExp=} expression The className expression which will be checked against all animations
5147            * @return {RegExp} The current CSS className expression value. If null then there is no expression value
5148            */
5149           this.classNameFilter = function(expression) {
5150             if (arguments.length === 1) {
5151               this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
5152               if (this.$$classNameFilter) {
5153                 var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
5154                 if (reservedRegex.test(this.$$classNameFilter.toString())) {
5155                   throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
5156
5157                 }
5158               }
5159             }
5160             return this.$$classNameFilter;
5161           };
5162
5163           this.$get = ['$$animateQueue', function($$animateQueue) {
5164             function domInsert(element, parentElement, afterElement) {
5165               // if for some reason the previous element was removed
5166               // from the dom sometime before this code runs then let's
5167               // just stick to using the parent element as the anchor
5168               if (afterElement) {
5169                 var afterNode = extractElementNode(afterElement);
5170                 if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
5171                   afterElement = null;
5172                 }
5173               }
5174               afterElement ? afterElement.after(element) : parentElement.prepend(element);
5175             }
5176
5177             /**
5178              * @ngdoc service
5179              * @name $animate
5180              * @description The $animate service exposes a series of DOM utility methods that provide support
5181              * for animation hooks. The default behavior is the application of DOM operations, however,
5182              * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
5183              * to ensure that animation runs with the triggered DOM operation.
5184              *
5185              * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
5186              * included and only when it is active then the animation hooks that `$animate` triggers will be
5187              * functional. Once active then all structural `ng-` directives will trigger animations as they perform
5188              * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
5189              * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
5190              *
5191              * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
5192              *
5193              * To learn more about enabling animation support, click here to visit the
5194              * {@link ngAnimate ngAnimate module page}.
5195              */
5196             return {
5197               // we don't call it directly since non-existant arguments may
5198               // be interpreted as null within the sub enabled function
5199
5200               /**
5201                *
5202                * @ngdoc method
5203                * @name $animate#on
5204                * @kind function
5205                * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
5206                *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
5207                *    is fired with the following params:
5208                *
5209                * ```js
5210                * $animate.on('enter', container,
5211                *    function callback(element, phase) {
5212                *      // cool we detected an enter animation within the container
5213                *    }
5214                * );
5215                * ```
5216                *
5217                * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
5218                * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
5219                *     as well as among its children
5220                * @param {Function} callback the callback function that will be fired when the listener is triggered
5221                *
5222                * The arguments present in the callback function are:
5223                * * `element` - The captured DOM element that the animation was fired on.
5224                * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
5225                */
5226               on: $$animateQueue.on,
5227
5228               /**
5229                *
5230                * @ngdoc method
5231                * @name $animate#off
5232                * @kind function
5233                * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
5234                * can be used in three different ways depending on the arguments:
5235                *
5236                * ```js
5237                * // remove all the animation event listeners listening for `enter`
5238                * $animate.off('enter');
5239                *
5240                * // remove all the animation event listeners listening for `enter` on the given element and its children
5241                * $animate.off('enter', container);
5242                *
5243                * // remove the event listener function provided by `listenerFn` that is set
5244                * // to listen for `enter` on the given `element` as well as its children
5245                * $animate.off('enter', container, callback);
5246                * ```
5247                *
5248                * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
5249                * @param {DOMElement=} container the container element the event listener was placed on
5250                * @param {Function=} callback the callback function that was registered as the listener
5251                */
5252               off: $$animateQueue.off,
5253
5254               /**
5255                * @ngdoc method
5256                * @name $animate#pin
5257                * @kind function
5258                * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
5259                *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
5260                *    element despite being outside the realm of the application or within another application. Say for example if the application
5261                *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
5262                *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
5263                *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
5264                *
5265                *    Note that this feature is only active when the `ngAnimate` module is used.
5266                *
5267                * @param {DOMElement} element the external element that will be pinned
5268                * @param {DOMElement} parentElement the host parent element that will be associated with the external element
5269                */
5270               pin: $$animateQueue.pin,
5271
5272               /**
5273                *
5274                * @ngdoc method
5275                * @name $animate#enabled
5276                * @kind function
5277                * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
5278                * function can be called in four ways:
5279                *
5280                * ```js
5281                * // returns true or false
5282                * $animate.enabled();
5283                *
5284                * // changes the enabled state for all animations
5285                * $animate.enabled(false);
5286                * $animate.enabled(true);
5287                *
5288                * // returns true or false if animations are enabled for an element
5289                * $animate.enabled(element);
5290                *
5291                * // changes the enabled state for an element and its children
5292                * $animate.enabled(element, true);
5293                * $animate.enabled(element, false);
5294                * ```
5295                *
5296                * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
5297                * @param {boolean=} enabled whether or not the animations will be enabled for the element
5298                *
5299                * @return {boolean} whether or not animations are enabled
5300                */
5301               enabled: $$animateQueue.enabled,
5302
5303               /**
5304                * @ngdoc method
5305                * @name $animate#cancel
5306                * @kind function
5307                * @description Cancels the provided animation.
5308                *
5309                * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
5310                */
5311               cancel: function(runner) {
5312                 runner.end && runner.end();
5313               },
5314
5315               /**
5316                *
5317                * @ngdoc method
5318                * @name $animate#enter
5319                * @kind function
5320                * @description Inserts the element into the DOM either after the `after` element (if provided) or
5321                *   as the first child within the `parent` element and then triggers an animation.
5322                *   A promise is returned that will be resolved during the next digest once the animation
5323                *   has completed.
5324                *
5325                * @param {DOMElement} element the element which will be inserted into the DOM
5326                * @param {DOMElement} parent the parent element which will append the element as
5327                *   a child (so long as the after element is not present)
5328                * @param {DOMElement=} after the sibling element after which the element will be appended
5329                * @param {object=} options an optional collection of options/styles that will be applied to the element
5330                *
5331                * @return {Promise} the animation callback promise
5332                */
5333               enter: function(element, parent, after, options) {
5334                 parent = parent && jqLite(parent);
5335                 after = after && jqLite(after);
5336                 parent = parent || after.parent();
5337                 domInsert(element, parent, after);
5338                 return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
5339               },
5340
5341               /**
5342                *
5343                * @ngdoc method
5344                * @name $animate#move
5345                * @kind function
5346                * @description Inserts (moves) the element into its new position in the DOM either after
5347                *   the `after` element (if provided) or as the first child within the `parent` element
5348                *   and then triggers an animation. A promise is returned that will be resolved
5349                *   during the next digest once the animation has completed.
5350                *
5351                * @param {DOMElement} element the element which will be moved into the new DOM position
5352                * @param {DOMElement} parent the parent element which will append the element as
5353                *   a child (so long as the after element is not present)
5354                * @param {DOMElement=} after the sibling element after which the element will be appended
5355                * @param {object=} options an optional collection of options/styles that will be applied to the element
5356                *
5357                * @return {Promise} the animation callback promise
5358                */
5359               move: function(element, parent, after, options) {
5360                 parent = parent && jqLite(parent);
5361                 after = after && jqLite(after);
5362                 parent = parent || after.parent();
5363                 domInsert(element, parent, after);
5364                 return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
5365               },
5366
5367               /**
5368                * @ngdoc method
5369                * @name $animate#leave
5370                * @kind function
5371                * @description Triggers an animation and then removes the element from the DOM.
5372                * When the function is called a promise is returned that will be resolved during the next
5373                * digest once the animation has completed.
5374                *
5375                * @param {DOMElement} element the element which will be removed from the DOM
5376                * @param {object=} options an optional collection of options/styles that will be applied to the element
5377                *
5378                * @return {Promise} the animation callback promise
5379                */
5380               leave: function(element, options) {
5381                 return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
5382                   element.remove();
5383                 });
5384               },
5385
5386               /**
5387                * @ngdoc method
5388                * @name $animate#addClass
5389                * @kind function
5390                *
5391                * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
5392                *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
5393                *   animation if element already contains the CSS class or if the class is removed at a later step.
5394                *   Note that class-based animations are treated differently compared to structural animations
5395                *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5396                *   depending if CSS or JavaScript animations are used.
5397                *
5398                * @param {DOMElement} element the element which the CSS classes will be applied to
5399                * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
5400                * @param {object=} options an optional collection of options/styles that will be applied to the element
5401                *
5402                * @return {Promise} the animation callback promise
5403                */
5404               addClass: function(element, className, options) {
5405                 options = prepareAnimateOptions(options);
5406                 options.addClass = mergeClasses(options.addclass, className);
5407                 return $$animateQueue.push(element, 'addClass', options);
5408               },
5409
5410               /**
5411                * @ngdoc method
5412                * @name $animate#removeClass
5413                * @kind function
5414                *
5415                * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
5416                *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
5417                *   animation if element does not contain the CSS class or if the class is added at a later step.
5418                *   Note that class-based animations are treated differently compared to structural animations
5419                *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5420                *   depending if CSS or JavaScript animations are used.
5421                *
5422                * @param {DOMElement} element the element which the CSS classes will be applied to
5423                * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
5424                * @param {object=} options an optional collection of options/styles that will be applied to the element
5425                *
5426                * @return {Promise} the animation callback promise
5427                */
5428               removeClass: function(element, className, options) {
5429                 options = prepareAnimateOptions(options);
5430                 options.removeClass = mergeClasses(options.removeClass, className);
5431                 return $$animateQueue.push(element, 'removeClass', options);
5432               },
5433
5434               /**
5435                * @ngdoc method
5436                * @name $animate#setClass
5437                * @kind function
5438                *
5439                * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
5440                *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
5441                *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
5442                *    passed. Note that class-based animations are treated differently compared to structural animations
5443                *    (like enter, move and leave) since the CSS classes may be added/removed at different points
5444                *    depending if CSS or JavaScript animations are used.
5445                *
5446                * @param {DOMElement} element the element which the CSS classes will be applied to
5447                * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
5448                * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
5449                * @param {object=} options an optional collection of options/styles that will be applied to the element
5450                *
5451                * @return {Promise} the animation callback promise
5452                */
5453               setClass: function(element, add, remove, options) {
5454                 options = prepareAnimateOptions(options);
5455                 options.addClass = mergeClasses(options.addClass, add);
5456                 options.removeClass = mergeClasses(options.removeClass, remove);
5457                 return $$animateQueue.push(element, 'setClass', options);
5458               },
5459
5460               /**
5461                * @ngdoc method
5462                * @name $animate#animate
5463                * @kind function
5464                *
5465                * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
5466                * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
5467                * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
5468                * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
5469                * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
5470                *
5471                * @param {DOMElement} element the element which the CSS styles will be applied to
5472                * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
5473                * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
5474                * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
5475                *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
5476                *    (Note that if no animation is detected then this value will not be appplied to the element.)
5477                * @param {object=} options an optional collection of options/styles that will be applied to the element
5478                *
5479                * @return {Promise} the animation callback promise
5480                */
5481               animate: function(element, from, to, className, options) {
5482                 options = prepareAnimateOptions(options);
5483                 options.from = options.from ? extend(options.from, from) : from;
5484                 options.to   = options.to   ? extend(options.to, to)     : to;
5485
5486                 className = className || 'ng-inline-animate';
5487                 options.tempClasses = mergeClasses(options.tempClasses, className);
5488                 return $$animateQueue.push(element, 'animate', options);
5489               }
5490             };
5491           }];
5492         }];
5493
5494         /**
5495          * @ngdoc service
5496          * @name $animateCss
5497          * @kind object
5498          *
5499          * @description
5500          * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
5501          * then the `$animateCss` service will actually perform animations.
5502          *
5503          * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
5504          */
5505         var $CoreAnimateCssProvider = function() {
5506           this.$get = ['$$rAF', '$q', function($$rAF, $q) {
5507
5508             var RAFPromise = function() {};
5509             RAFPromise.prototype = {
5510               done: function(cancel) {
5511                 this.defer && this.defer[cancel === true ? 'reject' : 'resolve']();
5512               },
5513               end: function() {
5514                 this.done();
5515               },
5516               cancel: function() {
5517                 this.done(true);
5518               },
5519               getPromise: function() {
5520                 if (!this.defer) {
5521                   this.defer = $q.defer();
5522                 }
5523                 return this.defer.promise;
5524               },
5525               then: function(f1,f2) {
5526                 return this.getPromise().then(f1,f2);
5527               },
5528               'catch': function(f1) {
5529                 return this.getPromise()['catch'](f1);
5530               },
5531               'finally': function(f1) {
5532                 return this.getPromise()['finally'](f1);
5533               }
5534             };
5535
5536             return function(element, options) {
5537               // there is no point in applying the styles since
5538               // there is no animation that goes on at all in
5539               // this version of $animateCss.
5540               if (options.cleanupStyles) {
5541                 options.from = options.to = null;
5542               }
5543
5544               if (options.from) {
5545                 element.css(options.from);
5546                 options.from = null;
5547               }
5548
5549               var closed, runner = new RAFPromise();
5550               return {
5551                 start: run,
5552                 end: run
5553               };
5554
5555               function run() {
5556                 $$rAF(function() {
5557                   close();
5558                   if (!closed) {
5559                     runner.done();
5560                   }
5561                   closed = true;
5562                 });
5563                 return runner;
5564               }
5565
5566               function close() {
5567                 if (options.addClass) {
5568                   element.addClass(options.addClass);
5569                   options.addClass = null;
5570                 }
5571                 if (options.removeClass) {
5572                   element.removeClass(options.removeClass);
5573                   options.removeClass = null;
5574                 }
5575                 if (options.to) {
5576                   element.css(options.to);
5577                   options.to = null;
5578                 }
5579               }
5580             };
5581           }];
5582         };
5583
5584         /* global stripHash: true */
5585
5586         /**
5587          * ! This is a private undocumented service !
5588          *
5589          * @name $browser
5590          * @requires $log
5591          * @description
5592          * This object has two goals:
5593          *
5594          * - hide all the global state in the browser caused by the window object
5595          * - abstract away all the browser specific features and inconsistencies
5596          *
5597          * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
5598          * service, which can be used for convenient testing of the application without the interaction with
5599          * the real browser apis.
5600          */
5601         /**
5602          * @param {object} window The global window object.
5603          * @param {object} document jQuery wrapped document.
5604          * @param {object} $log window.console or an object with the same interface.
5605          * @param {object} $sniffer $sniffer service
5606          */
5607         function Browser(window, document, $log, $sniffer) {
5608           var self = this,
5609               rawDocument = document[0],
5610               location = window.location,
5611               history = window.history,
5612               setTimeout = window.setTimeout,
5613               clearTimeout = window.clearTimeout,
5614               pendingDeferIds = {};
5615
5616           self.isMock = false;
5617
5618           var outstandingRequestCount = 0;
5619           var outstandingRequestCallbacks = [];
5620
5621           // TODO(vojta): remove this temporary api
5622           self.$$completeOutstandingRequest = completeOutstandingRequest;
5623           self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
5624
5625           /**
5626            * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
5627            * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
5628            */
5629           function completeOutstandingRequest(fn) {
5630             try {
5631               fn.apply(null, sliceArgs(arguments, 1));
5632             } finally {
5633               outstandingRequestCount--;
5634               if (outstandingRequestCount === 0) {
5635                 while (outstandingRequestCallbacks.length) {
5636                   try {
5637                     outstandingRequestCallbacks.pop()();
5638                   } catch (e) {
5639                     $log.error(e);
5640                   }
5641                 }
5642               }
5643             }
5644           }
5645
5646           function getHash(url) {
5647             var index = url.indexOf('#');
5648             return index === -1 ? '' : url.substr(index);
5649           }
5650
5651           /**
5652            * @private
5653            * Note: this method is used only by scenario runner
5654            * TODO(vojta): prefix this method with $$ ?
5655            * @param {function()} callback Function that will be called when no outstanding request
5656            */
5657           self.notifyWhenNoOutstandingRequests = function(callback) {
5658             if (outstandingRequestCount === 0) {
5659               callback();
5660             } else {
5661               outstandingRequestCallbacks.push(callback);
5662             }
5663           };
5664
5665           //////////////////////////////////////////////////////////////
5666           // URL API
5667           //////////////////////////////////////////////////////////////
5668
5669           var cachedState, lastHistoryState,
5670               lastBrowserUrl = location.href,
5671               baseElement = document.find('base'),
5672               pendingLocation = null;
5673
5674           cacheState();
5675           lastHistoryState = cachedState;
5676
5677           /**
5678            * @name $browser#url
5679            *
5680            * @description
5681            * GETTER:
5682            * Without any argument, this method just returns current value of location.href.
5683            *
5684            * SETTER:
5685            * With at least one argument, this method sets url to new value.
5686            * If html5 history api supported, pushState/replaceState is used, otherwise
5687            * location.href/location.replace is used.
5688            * Returns its own instance to allow chaining
5689            *
5690            * NOTE: this api is intended for use only by the $location service. Please use the
5691            * {@link ng.$location $location service} to change url.
5692            *
5693            * @param {string} url New url (when used as setter)
5694            * @param {boolean=} replace Should new url replace current history record?
5695            * @param {object=} state object to use with pushState/replaceState
5696            */
5697           self.url = function(url, replace, state) {
5698             // In modern browsers `history.state` is `null` by default; treating it separately
5699             // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
5700             // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
5701             if (isUndefined(state)) {
5702               state = null;
5703             }
5704
5705             // Android Browser BFCache causes location, history reference to become stale.
5706             if (location !== window.location) location = window.location;
5707             if (history !== window.history) history = window.history;
5708
5709             // setter
5710             if (url) {
5711               var sameState = lastHistoryState === state;
5712
5713               // Don't change anything if previous and current URLs and states match. This also prevents
5714               // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
5715               // See https://github.com/angular/angular.js/commit/ffb2701
5716               if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
5717                 return self;
5718               }
5719               var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
5720               lastBrowserUrl = url;
5721               lastHistoryState = state;
5722               // Don't use history API if only the hash changed
5723               // due to a bug in IE10/IE11 which leads
5724               // to not firing a `hashchange` nor `popstate` event
5725               // in some cases (see #9143).
5726               if ($sniffer.history && (!sameBase || !sameState)) {
5727                 history[replace ? 'replaceState' : 'pushState'](state, '', url);
5728                 cacheState();
5729                 // Do the assignment again so that those two variables are referentially identical.
5730                 lastHistoryState = cachedState;
5731               } else {
5732                 if (!sameBase || pendingLocation) {
5733                   pendingLocation = url;
5734                 }
5735                 if (replace) {
5736                   location.replace(url);
5737                 } else if (!sameBase) {
5738                   location.href = url;
5739                 } else {
5740                   location.hash = getHash(url);
5741                 }
5742                 if (location.href !== url) {
5743                   pendingLocation = url;
5744                 }
5745               }
5746               return self;
5747             // getter
5748             } else {
5749               // - pendingLocation is needed as browsers don't allow to read out
5750               //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
5751               //   https://openradar.appspot.com/22186109).
5752               // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
5753               return pendingLocation || location.href.replace(/%27/g,"'");
5754             }
5755           };
5756
5757           /**
5758            * @name $browser#state
5759            *
5760            * @description
5761            * This method is a getter.
5762            *
5763            * Return history.state or null if history.state is undefined.
5764            *
5765            * @returns {object} state
5766            */
5767           self.state = function() {
5768             return cachedState;
5769           };
5770
5771           var urlChangeListeners = [],
5772               urlChangeInit = false;
5773
5774           function cacheStateAndFireUrlChange() {
5775             pendingLocation = null;
5776             cacheState();
5777             fireUrlChange();
5778           }
5779
5780           function getCurrentState() {
5781             try {
5782               return history.state;
5783             } catch (e) {
5784               // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5785             }
5786           }
5787
5788           // This variable should be used *only* inside the cacheState function.
5789           var lastCachedState = null;
5790           function cacheState() {
5791             // This should be the only place in $browser where `history.state` is read.
5792             cachedState = getCurrentState();
5793             cachedState = isUndefined(cachedState) ? null : cachedState;
5794
5795             // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5796             if (equals(cachedState, lastCachedState)) {
5797               cachedState = lastCachedState;
5798             }
5799             lastCachedState = cachedState;
5800           }
5801
5802           function fireUrlChange() {
5803             if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
5804               return;
5805             }
5806
5807             lastBrowserUrl = self.url();
5808             lastHistoryState = cachedState;
5809             forEach(urlChangeListeners, function(listener) {
5810               listener(self.url(), cachedState);
5811             });
5812           }
5813
5814           /**
5815            * @name $browser#onUrlChange
5816            *
5817            * @description
5818            * Register callback function that will be called, when url changes.
5819            *
5820            * It's only called when the url is changed from outside of angular:
5821            * - user types different url into address bar
5822            * - user clicks on history (forward/back) button
5823            * - user clicks on a link
5824            *
5825            * It's not called when url is changed by $browser.url() method
5826            *
5827            * The listener gets called with new url as parameter.
5828            *
5829            * NOTE: this api is intended for use only by the $location service. Please use the
5830            * {@link ng.$location $location service} to monitor url changes in angular apps.
5831            *
5832            * @param {function(string)} listener Listener function to be called when url changes.
5833            * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
5834            */
5835           self.onUrlChange = function(callback) {
5836             // TODO(vojta): refactor to use node's syntax for events
5837             if (!urlChangeInit) {
5838               // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
5839               // don't fire popstate when user change the address bar and don't fire hashchange when url
5840               // changed by push/replaceState
5841
5842               // html5 history api - popstate event
5843               if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
5844               // hashchange event
5845               jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
5846
5847               urlChangeInit = true;
5848             }
5849
5850             urlChangeListeners.push(callback);
5851             return callback;
5852           };
5853
5854           /**
5855            * @private
5856            * Remove popstate and hashchange handler from window.
5857            *
5858            * NOTE: this api is intended for use only by $rootScope.
5859            */
5860           self.$$applicationDestroyed = function() {
5861             jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
5862           };
5863
5864           /**
5865            * Checks whether the url has changed outside of Angular.
5866            * Needs to be exported to be able to check for changes that have been done in sync,
5867            * as hashchange/popstate events fire in async.
5868            */
5869           self.$$checkUrlChange = fireUrlChange;
5870
5871           //////////////////////////////////////////////////////////////
5872           // Misc API
5873           //////////////////////////////////////////////////////////////
5874
5875           /**
5876            * @name $browser#baseHref
5877            *
5878            * @description
5879            * Returns current <base href>
5880            * (always relative - without domain)
5881            *
5882            * @returns {string} The current base href
5883            */
5884           self.baseHref = function() {
5885             var href = baseElement.attr('href');
5886             return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
5887           };
5888
5889           /**
5890            * @name $browser#defer
5891            * @param {function()} fn A function, who's execution should be deferred.
5892            * @param {number=} [delay=0] of milliseconds to defer the function execution.
5893            * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
5894            *
5895            * @description
5896            * Executes a fn asynchronously via `setTimeout(fn, delay)`.
5897            *
5898            * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
5899            * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
5900            * via `$browser.defer.flush()`.
5901            *
5902            */
5903           self.defer = function(fn, delay) {
5904             var timeoutId;
5905             outstandingRequestCount++;
5906             timeoutId = setTimeout(function() {
5907               delete pendingDeferIds[timeoutId];
5908               completeOutstandingRequest(fn);
5909             }, delay || 0);
5910             pendingDeferIds[timeoutId] = true;
5911             return timeoutId;
5912           };
5913
5914
5915           /**
5916            * @name $browser#defer.cancel
5917            *
5918            * @description
5919            * Cancels a deferred task identified with `deferId`.
5920            *
5921            * @param {*} deferId Token returned by the `$browser.defer` function.
5922            * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
5923            *                    canceled.
5924            */
5925           self.defer.cancel = function(deferId) {
5926             if (pendingDeferIds[deferId]) {
5927               delete pendingDeferIds[deferId];
5928               clearTimeout(deferId);
5929               completeOutstandingRequest(noop);
5930               return true;
5931             }
5932             return false;
5933           };
5934
5935         }
5936
5937         function $BrowserProvider() {
5938           this.$get = ['$window', '$log', '$sniffer', '$document',
5939               function($window, $log, $sniffer, $document) {
5940                 return new Browser($window, $document, $log, $sniffer);
5941               }];
5942         }
5943
5944         /**
5945          * @ngdoc service
5946          * @name $cacheFactory
5947          *
5948          * @description
5949          * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
5950          * them.
5951          *
5952          * ```js
5953          *
5954          *  var cache = $cacheFactory('cacheId');
5955          *  expect($cacheFactory.get('cacheId')).toBe(cache);
5956          *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
5957          *
5958          *  cache.put("key", "value");
5959          *  cache.put("another key", "another value");
5960          *
5961          *  // We've specified no options on creation
5962          *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
5963          *
5964          * ```
5965          *
5966          *
5967          * @param {string} cacheId Name or id of the newly created cache.
5968          * @param {object=} options Options object that specifies the cache behavior. Properties:
5969          *
5970          *   - `{number=}` `capacity` — turns the cache into LRU cache.
5971          *
5972          * @returns {object} Newly created cache object with the following set of methods:
5973          *
5974          * - `{object}` `info()` — Returns id, size, and options of cache.
5975          * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
5976          *   it.
5977          * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
5978          * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
5979          * - `{void}` `removeAll()` — Removes all cached values.
5980          * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
5981          *
5982          * @example
5983            <example module="cacheExampleApp">
5984              <file name="index.html">
5985                <div ng-controller="CacheController">
5986                  <input ng-model="newCacheKey" placeholder="Key">
5987                  <input ng-model="newCacheValue" placeholder="Value">
5988                  <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
5989
5990                  <p ng-if="keys.length">Cached Values</p>
5991                  <div ng-repeat="key in keys">
5992                    <span ng-bind="key"></span>
5993                    <span>: </span>
5994                    <b ng-bind="cache.get(key)"></b>
5995                  </div>
5996
5997                  <p>Cache Info</p>
5998                  <div ng-repeat="(key, value) in cache.info()">
5999                    <span ng-bind="key"></span>
6000                    <span>: </span>
6001                    <b ng-bind="value"></b>
6002                  </div>
6003                </div>
6004              </file>
6005              <file name="script.js">
6006                angular.module('cacheExampleApp', []).
6007                  controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
6008                    $scope.keys = [];
6009                    $scope.cache = $cacheFactory('cacheId');
6010                    $scope.put = function(key, value) {
6011                      if (angular.isUndefined($scope.cache.get(key))) {
6012                        $scope.keys.push(key);
6013                      }
6014                      $scope.cache.put(key, angular.isUndefined(value) ? null : value);
6015                    };
6016                  }]);
6017              </file>
6018              <file name="style.css">
6019                p {
6020                  margin: 10px 0 3px;
6021                }
6022              </file>
6023            </example>
6024          */
6025         function $CacheFactoryProvider() {
6026
6027           this.$get = function() {
6028             var caches = {};
6029
6030             function cacheFactory(cacheId, options) {
6031               if (cacheId in caches) {
6032                 throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
6033               }
6034
6035               var size = 0,
6036                   stats = extend({}, options, {id: cacheId}),
6037                   data = createMap(),
6038                   capacity = (options && options.capacity) || Number.MAX_VALUE,
6039                   lruHash = createMap(),
6040                   freshEnd = null,
6041                   staleEnd = null;
6042
6043               /**
6044                * @ngdoc type
6045                * @name $cacheFactory.Cache
6046                *
6047                * @description
6048                * A cache object used to store and retrieve data, primarily used by
6049                * {@link $http $http} and the {@link ng.directive:script script} directive to cache
6050                * templates and other data.
6051                *
6052                * ```js
6053                *  angular.module('superCache')
6054                *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
6055                *      return $cacheFactory('super-cache');
6056                *    }]);
6057                * ```
6058                *
6059                * Example test:
6060                *
6061                * ```js
6062                *  it('should behave like a cache', inject(function(superCache) {
6063                *    superCache.put('key', 'value');
6064                *    superCache.put('another key', 'another value');
6065                *
6066                *    expect(superCache.info()).toEqual({
6067                *      id: 'super-cache',
6068                *      size: 2
6069                *    });
6070                *
6071                *    superCache.remove('another key');
6072                *    expect(superCache.get('another key')).toBeUndefined();
6073                *
6074                *    superCache.removeAll();
6075                *    expect(superCache.info()).toEqual({
6076                *      id: 'super-cache',
6077                *      size: 0
6078                *    });
6079                *  }));
6080                * ```
6081                */
6082               return caches[cacheId] = {
6083
6084                 /**
6085                  * @ngdoc method
6086                  * @name $cacheFactory.Cache#put
6087                  * @kind function
6088                  *
6089                  * @description
6090                  * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
6091                  * retrieved later, and incrementing the size of the cache if the key was not already
6092                  * present in the cache. If behaving like an LRU cache, it will also remove stale
6093                  * entries from the set.
6094                  *
6095                  * It will not insert undefined values into the cache.
6096                  *
6097                  * @param {string} key the key under which the cached data is stored.
6098                  * @param {*} value the value to store alongside the key. If it is undefined, the key
6099                  *    will not be stored.
6100                  * @returns {*} the value stored.
6101                  */
6102                 put: function(key, value) {
6103                   if (isUndefined(value)) return;
6104                   if (capacity < Number.MAX_VALUE) {
6105                     var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
6106
6107                     refresh(lruEntry);
6108                   }
6109
6110                   if (!(key in data)) size++;
6111                   data[key] = value;
6112
6113                   if (size > capacity) {
6114                     this.remove(staleEnd.key);
6115                   }
6116
6117                   return value;
6118                 },
6119
6120                 /**
6121                  * @ngdoc method
6122                  * @name $cacheFactory.Cache#get
6123                  * @kind function
6124                  *
6125                  * @description
6126                  * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
6127                  *
6128                  * @param {string} key the key of the data to be retrieved
6129                  * @returns {*} the value stored.
6130                  */
6131                 get: function(key) {
6132                   if (capacity < Number.MAX_VALUE) {
6133                     var lruEntry = lruHash[key];
6134
6135                     if (!lruEntry) return;
6136
6137                     refresh(lruEntry);
6138                   }
6139
6140                   return data[key];
6141                 },
6142
6143
6144                 /**
6145                  * @ngdoc method
6146                  * @name $cacheFactory.Cache#remove
6147                  * @kind function
6148                  *
6149                  * @description
6150                  * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
6151                  *
6152                  * @param {string} key the key of the entry to be removed
6153                  */
6154                 remove: function(key) {
6155                   if (capacity < Number.MAX_VALUE) {
6156                     var lruEntry = lruHash[key];
6157
6158                     if (!lruEntry) return;
6159
6160                     if (lruEntry == freshEnd) freshEnd = lruEntry.p;
6161                     if (lruEntry == staleEnd) staleEnd = lruEntry.n;
6162                     link(lruEntry.n,lruEntry.p);
6163
6164                     delete lruHash[key];
6165                   }
6166
6167                   if (!(key in data)) return;
6168
6169                   delete data[key];
6170                   size--;
6171                 },
6172
6173
6174                 /**
6175                  * @ngdoc method
6176                  * @name $cacheFactory.Cache#removeAll
6177                  * @kind function
6178                  *
6179                  * @description
6180                  * Clears the cache object of any entries.
6181                  */
6182                 removeAll: function() {
6183                   data = createMap();
6184                   size = 0;
6185                   lruHash = createMap();
6186                   freshEnd = staleEnd = null;
6187                 },
6188
6189
6190                 /**
6191                  * @ngdoc method
6192                  * @name $cacheFactory.Cache#destroy
6193                  * @kind function
6194                  *
6195                  * @description
6196                  * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
6197                  * removing it from the {@link $cacheFactory $cacheFactory} set.
6198                  */
6199                 destroy: function() {
6200                   data = null;
6201                   stats = null;
6202                   lruHash = null;
6203                   delete caches[cacheId];
6204                 },
6205
6206
6207                 /**
6208                  * @ngdoc method
6209                  * @name $cacheFactory.Cache#info
6210                  * @kind function
6211                  *
6212                  * @description
6213                  * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
6214                  *
6215                  * @returns {object} an object with the following properties:
6216                  *   <ul>
6217                  *     <li>**id**: the id of the cache instance</li>
6218                  *     <li>**size**: the number of entries kept in the cache instance</li>
6219                  *     <li>**...**: any additional properties from the options object when creating the
6220                  *       cache.</li>
6221                  *   </ul>
6222                  */
6223                 info: function() {
6224                   return extend({}, stats, {size: size});
6225                 }
6226               };
6227
6228
6229               /**
6230                * makes the `entry` the freshEnd of the LRU linked list
6231                */
6232               function refresh(entry) {
6233                 if (entry != freshEnd) {
6234                   if (!staleEnd) {
6235                     staleEnd = entry;
6236                   } else if (staleEnd == entry) {
6237                     staleEnd = entry.n;
6238                   }
6239
6240                   link(entry.n, entry.p);
6241                   link(entry, freshEnd);
6242                   freshEnd = entry;
6243                   freshEnd.n = null;
6244                 }
6245               }
6246
6247
6248               /**
6249                * bidirectionally links two entries of the LRU linked list
6250                */
6251               function link(nextEntry, prevEntry) {
6252                 if (nextEntry != prevEntry) {
6253                   if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
6254                   if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
6255                 }
6256               }
6257             }
6258
6259
6260           /**
6261            * @ngdoc method
6262            * @name $cacheFactory#info
6263            *
6264            * @description
6265            * Get information about all the caches that have been created
6266            *
6267            * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
6268            */
6269             cacheFactory.info = function() {
6270               var info = {};
6271               forEach(caches, function(cache, cacheId) {
6272                 info[cacheId] = cache.info();
6273               });
6274               return info;
6275             };
6276
6277
6278           /**
6279            * @ngdoc method
6280            * @name $cacheFactory#get
6281            *
6282            * @description
6283            * Get access to a cache object by the `cacheId` used when it was created.
6284            *
6285            * @param {string} cacheId Name or id of a cache to access.
6286            * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
6287            */
6288             cacheFactory.get = function(cacheId) {
6289               return caches[cacheId];
6290             };
6291
6292
6293             return cacheFactory;
6294           };
6295         }
6296
6297         /**
6298          * @ngdoc service
6299          * @name $templateCache
6300          *
6301          * @description
6302          * The first time a template is used, it is loaded in the template cache for quick retrieval. You
6303          * can load templates directly into the cache in a `script` tag, or by consuming the
6304          * `$templateCache` service directly.
6305          *
6306          * Adding via the `script` tag:
6307          *
6308          * ```html
6309          *   <script type="text/ng-template" id="templateId.html">
6310          *     <p>This is the content of the template</p>
6311          *   </script>
6312          * ```
6313          *
6314          * **Note:** the `script` tag containing the template does not need to be included in the `head` of
6315          * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
6316          * element with ng-app attribute), otherwise the template will be ignored.
6317          *
6318          * Adding via the `$templateCache` service:
6319          *
6320          * ```js
6321          * var myApp = angular.module('myApp', []);
6322          * myApp.run(function($templateCache) {
6323          *   $templateCache.put('templateId.html', 'This is the content of the template');
6324          * });
6325          * ```
6326          *
6327          * To retrieve the template later, simply use it in your HTML:
6328          * ```html
6329          * <div ng-include=" 'templateId.html' "></div>
6330          * ```
6331          *
6332          * or get it via Javascript:
6333          * ```js
6334          * $templateCache.get('templateId.html')
6335          * ```
6336          *
6337          * See {@link ng.$cacheFactory $cacheFactory}.
6338          *
6339          */
6340         function $TemplateCacheProvider() {
6341           this.$get = ['$cacheFactory', function($cacheFactory) {
6342             return $cacheFactory('templates');
6343           }];
6344         }
6345
6346         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6347          *     Any commits to this file should be reviewed with security in mind.  *
6348          *   Changes to this file can potentially create security vulnerabilities. *
6349          *          An approval from 2 Core members with history of modifying      *
6350          *                         this file is required.                          *
6351          *                                                                         *
6352          *  Does the change somehow allow for arbitrary javascript to be executed? *
6353          *    Or allows for someone to change the prototype of built-in objects?   *
6354          *     Or gives undesired access to variables likes document or window?    *
6355          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6356
6357         /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
6358          *
6359          * DOM-related variables:
6360          *
6361          * - "node" - DOM Node
6362          * - "element" - DOM Element or Node
6363          * - "$node" or "$element" - jqLite-wrapped node or element
6364          *
6365          *
6366          * Compiler related stuff:
6367          *
6368          * - "linkFn" - linking fn of a single directive
6369          * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
6370          * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
6371          * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
6372          */
6373
6374
6375         /**
6376          * @ngdoc service
6377          * @name $compile
6378          * @kind function
6379          *
6380          * @description
6381          * Compiles an HTML string or DOM into a template and produces a template function, which
6382          * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
6383          *
6384          * The compilation is a process of walking the DOM tree and matching DOM elements to
6385          * {@link ng.$compileProvider#directive directives}.
6386          *
6387          * <div class="alert alert-warning">
6388          * **Note:** This document is an in-depth reference of all directive options.
6389          * For a gentle introduction to directives with examples of common use cases,
6390          * see the {@link guide/directive directive guide}.
6391          * </div>
6392          *
6393          * ## Comprehensive Directive API
6394          *
6395          * There are many different options for a directive.
6396          *
6397          * The difference resides in the return value of the factory function.
6398          * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
6399          * or just the `postLink` function (all other properties will have the default values).
6400          *
6401          * <div class="alert alert-success">
6402          * **Best Practice:** It's recommended to use the "directive definition object" form.
6403          * </div>
6404          *
6405          * Here's an example directive declared with a Directive Definition Object:
6406          *
6407          * ```js
6408          *   var myModule = angular.module(...);
6409          *
6410          *   myModule.directive('directiveName', function factory(injectables) {
6411          *     var directiveDefinitionObject = {
6412          *       priority: 0,
6413          *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
6414          *       // or
6415          *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
6416          *       transclude: false,
6417          *       restrict: 'A',
6418          *       templateNamespace: 'html',
6419          *       scope: false,
6420          *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
6421          *       controllerAs: 'stringIdentifier',
6422          *       bindToController: false,
6423          *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
6424          *       compile: function compile(tElement, tAttrs, transclude) {
6425          *         return {
6426          *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6427          *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
6428          *         }
6429          *         // or
6430          *         // return function postLink( ... ) { ... }
6431          *       },
6432          *       // or
6433          *       // link: {
6434          *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6435          *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
6436          *       // }
6437          *       // or
6438          *       // link: function postLink( ... ) { ... }
6439          *     };
6440          *     return directiveDefinitionObject;
6441          *   });
6442          * ```
6443          *
6444          * <div class="alert alert-warning">
6445          * **Note:** Any unspecified options will use the default value. You can see the default values below.
6446          * </div>
6447          *
6448          * Therefore the above can be simplified as:
6449          *
6450          * ```js
6451          *   var myModule = angular.module(...);
6452          *
6453          *   myModule.directive('directiveName', function factory(injectables) {
6454          *     var directiveDefinitionObject = {
6455          *       link: function postLink(scope, iElement, iAttrs) { ... }
6456          *     };
6457          *     return directiveDefinitionObject;
6458          *     // or
6459          *     // return function postLink(scope, iElement, iAttrs) { ... }
6460          *   });
6461          * ```
6462          *
6463          *
6464          *
6465          * ### Directive Definition Object
6466          *
6467          * The directive definition object provides instructions to the {@link ng.$compile
6468          * compiler}. The attributes are:
6469          *
6470          * #### `multiElement`
6471          * When this property is set to true, the HTML compiler will collect DOM nodes between
6472          * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
6473          * together as the directive elements. It is recommended that this feature be used on directives
6474          * which are not strictly behavioural (such as {@link ngClick}), and which
6475          * do not manipulate or replace child nodes (such as {@link ngInclude}).
6476          *
6477          * #### `priority`
6478          * When there are multiple directives defined on a single DOM element, sometimes it
6479          * is necessary to specify the order in which the directives are applied. The `priority` is used
6480          * to sort the directives before their `compile` functions get called. Priority is defined as a
6481          * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
6482          * are also run in priority order, but post-link functions are run in reverse order. The order
6483          * of directives with the same priority is undefined. The default priority is `0`.
6484          *
6485          * #### `terminal`
6486          * If set to true then the current `priority` will be the last set of directives
6487          * which will execute (any directives at the current priority will still execute
6488          * as the order of execution on same `priority` is undefined). Note that expressions
6489          * and other directives used in the directive's template will also be excluded from execution.
6490          *
6491          * #### `scope`
6492          * The scope property can be `true`, an object or a falsy value:
6493          *
6494          * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
6495          *
6496          * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
6497          * the directive's element. If multiple directives on the same element request a new scope,
6498          * only one new scope is created. The new scope rule does not apply for the root of the template
6499          * since the root of the template always gets a new scope.
6500          *
6501          * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
6502          * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
6503          * scope. This is useful when creating reusable components, which should not accidentally read or modify
6504          * data in the parent scope.
6505          *
6506          * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
6507          * directive's element. These local properties are useful for aliasing values for templates. The keys in
6508          * the object hash map to the name of the property on the isolate scope; the values define how the property
6509          * is bound to the parent scope, via matching attributes on the directive's element:
6510          *
6511          * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
6512          *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
6513          *   attribute name is assumed to be the same as the local name.
6514          *   Given `<widget my-attr="hello {{name}}">` and widget definition
6515          *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
6516          *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
6517          *   `localName` property on the widget scope. The `name` is read from the parent scope (not
6518          *   component scope).
6519          *
6520          * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
6521          *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
6522          *   name is specified then the attribute name is assumed to be the same as the local name.
6523          *   Given `<widget my-attr="parentModel">` and widget definition of
6524          *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
6525          *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
6526          *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
6527          *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
6528          *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
6529          *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
6530          *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
6531          *
6532          * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
6533          *   If no `attr` name is specified then the attribute name is assumed to be the same as the
6534          *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
6535          *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
6536          *   a function wrapper for the `count = count + value` expression. Often it's desirable to
6537          *   pass data from the isolated scope via an expression to the parent scope, this can be
6538          *   done by passing a map of local variable names and values into the expression wrapper fn.
6539          *   For example, if the expression is `increment(amount)` then we can specify the amount value
6540          *   by calling the `localFn` as `localFn({amount: 22})`.
6541          *
6542          * In general it's possible to apply more than one directive to one element, but there might be limitations
6543          * depending on the type of scope required by the directives. The following points will help explain these limitations.
6544          * For simplicity only two directives are taken into account, but it is also applicable for several directives:
6545          *
6546          * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
6547          * * **child scope** + **no scope** =>  Both directives will share one single child scope
6548          * * **child scope** + **child scope** =>  Both directives will share one single child scope
6549          * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
6550          * its parent's scope
6551          * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
6552          * be applied to the same element.
6553          * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
6554          * cannot be applied to the same element.
6555          *
6556          *
6557          * #### `bindToController`
6558          * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
6559          * allow a component to have its properties bound to the controller, rather than to scope. When the controller
6560          * is instantiated, the initial values of the isolate scope bindings are already available.
6561          *
6562          * #### `controller`
6563          * Controller constructor function. The controller is instantiated before the
6564          * pre-linking phase and can be accessed by other directives (see
6565          * `require` attribute). This allows the directives to communicate with each other and augment
6566          * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
6567          *
6568          * * `$scope` - Current scope associated with the element
6569          * * `$element` - Current element
6570          * * `$attrs` - Current attributes object for the element
6571          * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
6572          *   `function([scope], cloneLinkingFn, futureParentElement)`.
6573          *    * `scope`: optional argument to override the scope.
6574          *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
6575          *    * `futureParentElement`:
6576          *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
6577          *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
6578          *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
6579          *          and when the `cloneLinkinFn` is passed,
6580          *          as those elements need to created and cloned in a special way when they are defined outside their
6581          *          usual containers (e.g. like `<svg>`).
6582          *        * See also the `directive.templateNamespace` property.
6583          *
6584          *
6585          * #### `require`
6586          * Require another directive and inject its controller as the fourth argument to the linking function. The
6587          * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
6588          * injected argument will be an array in corresponding order. If no such directive can be
6589          * found, or if the directive does not have a controller, then an error is raised (unless no link function
6590          * is specified, in which case error checking is skipped). The name can be prefixed with:
6591          *
6592          * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
6593          * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
6594          * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
6595          * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
6596          * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
6597          *   `null` to the `link` fn if not found.
6598          * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
6599          *   `null` to the `link` fn if not found.
6600          *
6601          *
6602          * #### `controllerAs`
6603          * Identifier name for a reference to the controller in the directive's scope.
6604          * This allows the controller to be referenced from the directive template. This is especially
6605          * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
6606          * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
6607          * `controllerAs` reference might overwrite a property that already exists on the parent scope.
6608          *
6609          *
6610          * #### `restrict`
6611          * String of subset of `EACM` which restricts the directive to a specific directive
6612          * declaration style. If omitted, the defaults (elements and attributes) are used.
6613          *
6614          * * `E` - Element name (default): `<my-directive></my-directive>`
6615          * * `A` - Attribute (default): `<div my-directive="exp"></div>`
6616          * * `C` - Class: `<div class="my-directive: exp;"></div>`
6617          * * `M` - Comment: `<!-- directive: my-directive exp -->`
6618          *
6619          *
6620          * #### `templateNamespace`
6621          * String representing the document type used by the markup in the template.
6622          * AngularJS needs this information as those elements need to be created and cloned
6623          * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
6624          *
6625          * * `html` - All root nodes in the template are HTML. Root nodes may also be
6626          *   top-level elements such as `<svg>` or `<math>`.
6627          * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
6628          * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
6629          *
6630          * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
6631          *
6632          * #### `template`
6633          * HTML markup that may:
6634          * * Replace the contents of the directive's element (default).
6635          * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
6636          * * Wrap the contents of the directive's element (if `transclude` is true).
6637          *
6638          * Value may be:
6639          *
6640          * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
6641          * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
6642          *   function api below) and returns a string value.
6643          *
6644          *
6645          * #### `templateUrl`
6646          * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
6647          *
6648          * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
6649          * for later when the template has been resolved.  In the meantime it will continue to compile and link
6650          * sibling and parent elements as though this element had not contained any directives.
6651          *
6652          * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
6653          * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
6654          * case when only one deeply nested directive has `templateUrl`.
6655          *
6656          * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
6657          *
6658          * You can specify `templateUrl` as a string representing the URL or as a function which takes two
6659          * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
6660          * a string value representing the url.  In either case, the template URL is passed through {@link
6661          * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
6662          *
6663          *
6664          * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
6665          * specify what the template should replace. Defaults to `false`.
6666          *
6667          * * `true` - the template will replace the directive's element.
6668          * * `false` - the template will replace the contents of the directive's element.
6669          *
6670          * The replacement process migrates all of the attributes / classes from the old element to the new
6671          * one. See the {@link guide/directive#template-expanding-directive
6672          * Directives Guide} for an example.
6673          *
6674          * There are very few scenarios where element replacement is required for the application function,
6675          * the main one being reusable custom components that are used within SVG contexts
6676          * (because SVG doesn't work with custom elements in the DOM tree).
6677          *
6678          * #### `transclude`
6679          * Extract the contents of the element where the directive appears and make it available to the directive.
6680          * The contents are compiled and provided to the directive as a **transclusion function**. See the
6681          * {@link $compile#transclusion Transclusion} section below.
6682          *
6683          * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6684          * directive's element or the entire element:
6685          *
6686          * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6687          * * `'element'` - transclude the whole of the directive's element including any directives on this
6688          *   element that defined at a lower priority than this directive. When used, the `template`
6689          *   property is ignored.
6690          *
6691          *
6692          * #### `compile`
6693          *
6694          * ```js
6695          *   function compile(tElement, tAttrs, transclude) { ... }
6696          * ```
6697          *
6698          * The compile function deals with transforming the template DOM. Since most directives do not do
6699          * template transformation, it is not used often. The compile function takes the following arguments:
6700          *
6701          *   * `tElement` - template element - The element where the directive has been declared. It is
6702          *     safe to do template transformation on the element and child elements only.
6703          *
6704          *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
6705          *     between all directive compile functions.
6706          *
6707          *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
6708          *
6709          * <div class="alert alert-warning">
6710          * **Note:** The template instance and the link instance may be different objects if the template has
6711          * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
6712          * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
6713          * should be done in a linking function rather than in a compile function.
6714          * </div>
6715
6716          * <div class="alert alert-warning">
6717          * **Note:** The compile function cannot handle directives that recursively use themselves in their
6718          * own templates or compile functions. Compiling these directives results in an infinite loop and a
6719          * stack overflow errors.
6720          *
6721          * This can be avoided by manually using $compile in the postLink function to imperatively compile
6722          * a directive's template instead of relying on automatic template compilation via `template` or
6723          * `templateUrl` declaration or manual compilation inside the compile function.
6724          * </div>
6725          *
6726          * <div class="alert alert-danger">
6727          * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
6728          *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
6729          *   to the link function instead.
6730          * </div>
6731
6732          * A compile function can have a return value which can be either a function or an object.
6733          *
6734          * * returning a (post-link) function - is equivalent to registering the linking function via the
6735          *   `link` property of the config object when the compile function is empty.
6736          *
6737          * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
6738          *   control when a linking function should be called during the linking phase. See info about
6739          *   pre-linking and post-linking functions below.
6740          *
6741          *
6742          * #### `link`
6743          * This property is used only if the `compile` property is not defined.
6744          *
6745          * ```js
6746          *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
6747          * ```
6748          *
6749          * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
6750          * executed after the template has been cloned. This is where most of the directive logic will be
6751          * put.
6752          *
6753          *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
6754          *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
6755          *
6756          *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
6757          *     manipulate the children of the element only in `postLink` function since the children have
6758          *     already been linked.
6759          *
6760          *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
6761          *     between all directive linking functions.
6762          *
6763          *   * `controller` - the directive's required controller instance(s) - Instances are shared
6764          *     among all directives, which allows the directives to use the controllers as a communication
6765          *     channel. The exact value depends on the directive's `require` property:
6766          *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
6767          *       * `string`: the controller instance
6768          *       * `array`: array of controller instances
6769          *
6770          *     If a required controller cannot be found, and it is optional, the instance is `null`,
6771          *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
6772          *
6773          *     Note that you can also require the directive's own controller - it will be made available like
6774          *     any other controller.
6775          *
6776          *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
6777          *     This is the same as the `$transclude`
6778          *     parameter of directive controllers, see there for details.
6779          *     `function([scope], cloneLinkingFn, futureParentElement)`.
6780          *
6781          * #### Pre-linking function
6782          *
6783          * Executed before the child elements are linked. Not safe to do DOM transformation since the
6784          * compiler linking function will fail to locate the correct elements for linking.
6785          *
6786          * #### Post-linking function
6787          *
6788          * Executed after the child elements are linked.
6789          *
6790          * Note that child elements that contain `templateUrl` directives will not have been compiled
6791          * and linked since they are waiting for their template to load asynchronously and their own
6792          * compilation and linking has been suspended until that occurs.
6793          *
6794          * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
6795          * for their async templates to be resolved.
6796          *
6797          *
6798          * ### Transclusion
6799          *
6800          * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
6801          * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
6802          * scope from where they were taken.
6803          *
6804          * Transclusion is used (often with {@link ngTransclude}) to insert the
6805          * original contents of a directive's element into a specified place in the template of the directive.
6806          * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
6807          * content has access to the properties on the scope from which it was taken, even if the directive
6808          * has isolated scope.
6809          * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
6810          *
6811          * This makes it possible for the widget to have private state for its template, while the transcluded
6812          * content has access to its originating scope.
6813          *
6814          * <div class="alert alert-warning">
6815          * **Note:** When testing an element transclude directive you must not place the directive at the root of the
6816          * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
6817          * Testing Transclusion Directives}.
6818          * </div>
6819          *
6820          * #### Transclusion Functions
6821          *
6822          * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
6823          * function** to the directive's `link` function and `controller`. This transclusion function is a special
6824          * **linking function** that will return the compiled contents linked to a new transclusion scope.
6825          *
6826          * <div class="alert alert-info">
6827          * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
6828          * ngTransclude will deal with it for us.
6829          * </div>
6830          *
6831          * If you want to manually control the insertion and removal of the transcluded content in your directive
6832          * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
6833          * object that contains the compiled DOM, which is linked to the correct transclusion scope.
6834          *
6835          * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
6836          * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
6837          * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6838          *
6839          * <div class="alert alert-info">
6840          * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
6841          * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6842          * </div>
6843          *
6844          * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
6845          * attach function**:
6846          *
6847          * ```js
6848          * var transcludedContent, transclusionScope;
6849          *
6850          * $transclude(function(clone, scope) {
6851          *   element.append(clone);
6852          *   transcludedContent = clone;
6853          *   transclusionScope = scope;
6854          * });
6855          * ```
6856          *
6857          * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
6858          * associated transclusion scope:
6859          *
6860          * ```js
6861          * transcludedContent.remove();
6862          * transclusionScope.$destroy();
6863          * ```
6864          *
6865          * <div class="alert alert-info">
6866          * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
6867          * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
6868          * then you are also responsible for calling `$destroy` on the transclusion scope.
6869          * </div>
6870          *
6871          * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6872          * automatically destroy their transluded clones as necessary so you do not need to worry about this if
6873          * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6874          *
6875          *
6876          * #### Transclusion Scopes
6877          *
6878          * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
6879          * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
6880          * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
6881          * was taken.
6882          *
6883          * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
6884          * like this:
6885          *
6886          * ```html
6887          * <div ng-app>
6888          *   <div isolate>
6889          *     <div transclusion>
6890          *     </div>
6891          *   </div>
6892          * </div>
6893          * ```
6894          *
6895          * The `$parent` scope hierarchy will look like this:
6896          *
6897          * ```
6898          * - $rootScope
6899          *   - isolate
6900          *     - transclusion
6901          * ```
6902          *
6903          * but the scopes will inherit prototypically from different scopes to their `$parent`.
6904          *
6905          * ```
6906          * - $rootScope
6907          *   - transclusion
6908          * - isolate
6909          * ```
6910          *
6911          *
6912          * ### Attributes
6913          *
6914          * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6915          * `link()` or `compile()` functions. It has a variety of uses.
6916          *
6917          * accessing *Normalized attribute names:*
6918          * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6919          * the attributes object allows for normalized access to
6920          *   the attributes.
6921          *
6922          * * *Directive inter-communication:* All directives share the same instance of the attributes
6923          *   object which allows the directives to use the attributes object as inter directive
6924          *   communication.
6925          *
6926          * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
6927          *   allowing other directives to read the interpolated value.
6928          *
6929          * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
6930          *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
6931          *   the only way to easily get the actual value because during the linking phase the interpolation
6932          *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
6933          *
6934          * ```js
6935          * function linkingFn(scope, elm, attrs, ctrl) {
6936          *   // get the attribute value
6937          *   console.log(attrs.ngModel);
6938          *
6939          *   // change the attribute
6940          *   attrs.$set('ngModel', 'new value');
6941          *
6942          *   // observe changes to interpolated attribute
6943          *   attrs.$observe('ngModel', function(value) {
6944          *     console.log('ngModel has changed value to ' + value);
6945          *   });
6946          * }
6947          * ```
6948          *
6949          * ## Example
6950          *
6951          * <div class="alert alert-warning">
6952          * **Note**: Typically directives are registered with `module.directive`. The example below is
6953          * to illustrate how `$compile` works.
6954          * </div>
6955          *
6956          <example module="compileExample">
6957            <file name="index.html">
6958             <script>
6959               angular.module('compileExample', [], function($compileProvider) {
6960                 // configure new 'compile' directive by passing a directive
6961                 // factory function. The factory function injects the '$compile'
6962                 $compileProvider.directive('compile', function($compile) {
6963                   // directive factory creates a link function
6964                   return function(scope, element, attrs) {
6965                     scope.$watch(
6966                       function(scope) {
6967                          // watch the 'compile' expression for changes
6968                         return scope.$eval(attrs.compile);
6969                       },
6970                       function(value) {
6971                         // when the 'compile' expression changes
6972                         // assign it into the current DOM
6973                         element.html(value);
6974
6975                         // compile the new DOM and link it to the current
6976                         // scope.
6977                         // NOTE: we only compile .childNodes so that
6978                         // we don't get into infinite loop compiling ourselves
6979                         $compile(element.contents())(scope);
6980                       }
6981                     );
6982                   };
6983                 });
6984               })
6985               .controller('GreeterController', ['$scope', function($scope) {
6986                 $scope.name = 'Angular';
6987                 $scope.html = 'Hello {{name}}';
6988               }]);
6989             </script>
6990             <div ng-controller="GreeterController">
6991               <input ng-model="name"> <br/>
6992               <textarea ng-model="html"></textarea> <br/>
6993               <div compile="html"></div>
6994             </div>
6995            </file>
6996            <file name="protractor.js" type="protractor">
6997              it('should auto compile', function() {
6998                var textarea = $('textarea');
6999                var output = $('div[compile]');
7000                // The initial state reads 'Hello Angular'.
7001                expect(output.getText()).toBe('Hello Angular');
7002                textarea.clear();
7003                textarea.sendKeys('{{name}}!');
7004                expect(output.getText()).toBe('Angular!');
7005              });
7006            </file>
7007          </example>
7008
7009          *
7010          *
7011          * @param {string|DOMElement} element Element or HTML string to compile into a template function.
7012          * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
7013          *
7014          * <div class="alert alert-danger">
7015          * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
7016          *   e.g. will not use the right outer scope. Please pass the transclude function as a
7017          *   `parentBoundTranscludeFn` to the link function instead.
7018          * </div>
7019          *
7020          * @param {number} maxPriority only apply directives lower than given priority (Only effects the
7021          *                 root element(s), not their children)
7022          * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
7023          * (a DOM element/tree) to a scope. Where:
7024          *
7025          *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
7026          *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
7027          *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
7028          *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
7029          *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
7030          *
7031          *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
7032          *      * `scope` - is the current scope with which the linking function is working with.
7033          *
7034          *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
7035          *  keys may be used to control linking behavior:
7036          *
7037          *      * `parentBoundTranscludeFn` - the transclude function made available to
7038          *        directives; if given, it will be passed through to the link functions of
7039          *        directives found in `element` during compilation.
7040          *      * `transcludeControllers` - an object hash with keys that map controller names
7041          *        to controller instances; if given, it will make the controllers
7042          *        available to directives.
7043          *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
7044          *        the cloned elements; only needed for transcludes that are allowed to contain non html
7045          *        elements (e.g. SVG elements). See also the directive.controller property.
7046          *
7047          * Calling the linking function returns the element of the template. It is either the original
7048          * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
7049          *
7050          * After linking the view is not updated until after a call to $digest which typically is done by
7051          * Angular automatically.
7052          *
7053          * If you need access to the bound view, there are two ways to do it:
7054          *
7055          * - If you are not asking the linking function to clone the template, create the DOM element(s)
7056          *   before you send them to the compiler and keep this reference around.
7057          *   ```js
7058          *     var element = $compile('<p>{{total}}</p>')(scope);
7059          *   ```
7060          *
7061          * - if on the other hand, you need the element to be cloned, the view reference from the original
7062          *   example would not point to the clone, but rather to the original template that was cloned. In
7063          *   this case, you can access the clone via the cloneAttachFn:
7064          *   ```js
7065          *     var templateElement = angular.element('<p>{{total}}</p>'),
7066          *         scope = ....;
7067          *
7068          *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
7069          *       //attach the clone to DOM document at the right place
7070          *     });
7071          *
7072          *     //now we have reference to the cloned DOM via `clonedElement`
7073          *   ```
7074          *
7075          *
7076          * For information on how the compiler works, see the
7077          * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
7078          */
7079
7080         var $compileMinErr = minErr('$compile');
7081
7082         /**
7083          * @ngdoc provider
7084          * @name $compileProvider
7085          *
7086          * @description
7087          */
7088         $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
7089         function $CompileProvider($provide, $$sanitizeUriProvider) {
7090           var hasDirectives = {},
7091               Suffix = 'Directive',
7092               COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
7093               CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
7094               ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
7095               REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
7096
7097           // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
7098           // The assumption is that future DOM event attribute names will begin with
7099           // 'on' and be composed of only English letters.
7100           var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
7101
7102           function parseIsolateBindings(scope, directiveName, isController) {
7103             var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
7104
7105             var bindings = {};
7106
7107             forEach(scope, function(definition, scopeName) {
7108               var match = definition.match(LOCAL_REGEXP);
7109
7110               if (!match) {
7111                 throw $compileMinErr('iscp',
7112                     "Invalid {3} for directive '{0}'." +
7113                     " Definition: {... {1}: '{2}' ...}",
7114                     directiveName, scopeName, definition,
7115                     (isController ? "controller bindings definition" :
7116                     "isolate scope definition"));
7117               }
7118
7119               bindings[scopeName] = {
7120                 mode: match[1][0],
7121                 collection: match[2] === '*',
7122                 optional: match[3] === '?',
7123                 attrName: match[4] || scopeName
7124               };
7125             });
7126
7127             return bindings;
7128           }
7129
7130           function parseDirectiveBindings(directive, directiveName) {
7131             var bindings = {
7132               isolateScope: null,
7133               bindToController: null
7134             };
7135             if (isObject(directive.scope)) {
7136               if (directive.bindToController === true) {
7137                 bindings.bindToController = parseIsolateBindings(directive.scope,
7138                                                                  directiveName, true);
7139                 bindings.isolateScope = {};
7140               } else {
7141                 bindings.isolateScope = parseIsolateBindings(directive.scope,
7142                                                              directiveName, false);
7143               }
7144             }
7145             if (isObject(directive.bindToController)) {
7146               bindings.bindToController =
7147                   parseIsolateBindings(directive.bindToController, directiveName, true);
7148             }
7149             if (isObject(bindings.bindToController)) {
7150               var controller = directive.controller;
7151               var controllerAs = directive.controllerAs;
7152               if (!controller) {
7153                 // There is no controller, there may or may not be a controllerAs property
7154                 throw $compileMinErr('noctrl',
7155                       "Cannot bind to controller without directive '{0}'s controller.",
7156                       directiveName);
7157               } else if (!identifierForController(controller, controllerAs)) {
7158                 // There is a controller, but no identifier or controllerAs property
7159                 throw $compileMinErr('noident',
7160                       "Cannot bind to controller without identifier for directive '{0}'.",
7161                       directiveName);
7162               }
7163             }
7164             return bindings;
7165           }
7166
7167           function assertValidDirectiveName(name) {
7168             var letter = name.charAt(0);
7169             if (!letter || letter !== lowercase(letter)) {
7170               throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
7171             }
7172             if (name !== name.trim()) {
7173               throw $compileMinErr('baddir',
7174                     "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
7175                     name);
7176             }
7177           }
7178
7179           /**
7180            * @ngdoc method
7181            * @name $compileProvider#directive
7182            * @kind function
7183            *
7184            * @description
7185            * Register a new directive with the compiler.
7186            *
7187            * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
7188            *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
7189            *    names and the values are the factories.
7190            * @param {Function|Array} directiveFactory An injectable directive factory function. See
7191            *    {@link guide/directive} for more info.
7192            * @returns {ng.$compileProvider} Self for chaining.
7193            */
7194            this.directive = function registerDirective(name, directiveFactory) {
7195             assertNotHasOwnProperty(name, 'directive');
7196             if (isString(name)) {
7197               assertValidDirectiveName(name);
7198               assertArg(directiveFactory, 'directiveFactory');
7199               if (!hasDirectives.hasOwnProperty(name)) {
7200                 hasDirectives[name] = [];
7201                 $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
7202                   function($injector, $exceptionHandler) {
7203                     var directives = [];
7204                     forEach(hasDirectives[name], function(directiveFactory, index) {
7205                       try {
7206                         var directive = $injector.invoke(directiveFactory);
7207                         if (isFunction(directive)) {
7208                           directive = { compile: valueFn(directive) };
7209                         } else if (!directive.compile && directive.link) {
7210                           directive.compile = valueFn(directive.link);
7211                         }
7212                         directive.priority = directive.priority || 0;
7213                         directive.index = index;
7214                         directive.name = directive.name || name;
7215                         directive.require = directive.require || (directive.controller && directive.name);
7216                         directive.restrict = directive.restrict || 'EA';
7217                         var bindings = directive.$$bindings =
7218                             parseDirectiveBindings(directive, directive.name);
7219                         if (isObject(bindings.isolateScope)) {
7220                           directive.$$isolateBindings = bindings.isolateScope;
7221                         }
7222                         directive.$$moduleName = directiveFactory.$$moduleName;
7223                         directives.push(directive);
7224                       } catch (e) {
7225                         $exceptionHandler(e);
7226                       }
7227                     });
7228                     return directives;
7229                   }]);
7230               }
7231               hasDirectives[name].push(directiveFactory);
7232             } else {
7233               forEach(name, reverseParams(registerDirective));
7234             }
7235             return this;
7236           };
7237
7238
7239           /**
7240            * @ngdoc method
7241            * @name $compileProvider#aHrefSanitizationWhitelist
7242            * @kind function
7243            *
7244            * @description
7245            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
7246            * urls during a[href] sanitization.
7247            *
7248            * The sanitization is a security measure aimed at preventing XSS attacks via html links.
7249            *
7250            * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
7251            * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
7252            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
7253            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
7254            *
7255            * @param {RegExp=} regexp New regexp to whitelist urls with.
7256            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
7257            *    chaining otherwise.
7258            */
7259           this.aHrefSanitizationWhitelist = function(regexp) {
7260             if (isDefined(regexp)) {
7261               $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
7262               return this;
7263             } else {
7264               return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
7265             }
7266           };
7267
7268
7269           /**
7270            * @ngdoc method
7271            * @name $compileProvider#imgSrcSanitizationWhitelist
7272            * @kind function
7273            *
7274            * @description
7275            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
7276            * urls during img[src] sanitization.
7277            *
7278            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
7279            *
7280            * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
7281            * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
7282            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
7283            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
7284            *
7285            * @param {RegExp=} regexp New regexp to whitelist urls with.
7286            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
7287            *    chaining otherwise.
7288            */
7289           this.imgSrcSanitizationWhitelist = function(regexp) {
7290             if (isDefined(regexp)) {
7291               $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
7292               return this;
7293             } else {
7294               return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
7295             }
7296           };
7297
7298           /**
7299            * @ngdoc method
7300            * @name  $compileProvider#debugInfoEnabled
7301            *
7302            * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
7303            * current debugInfoEnabled state
7304            * @returns {*} current value if used as getter or itself (chaining) if used as setter
7305            *
7306            * @kind function
7307            *
7308            * @description
7309            * Call this method to enable/disable various debug runtime information in the compiler such as adding
7310            * binding information and a reference to the current scope on to DOM elements.
7311            * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
7312            * * `ng-binding` CSS class
7313            * * `$binding` data property containing an array of the binding expressions
7314            *
7315            * You may want to disable this in production for a significant performance boost. See
7316            * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
7317            *
7318            * The default value is true.
7319            */
7320           var debugInfoEnabled = true;
7321           this.debugInfoEnabled = function(enabled) {
7322             if (isDefined(enabled)) {
7323               debugInfoEnabled = enabled;
7324               return this;
7325             }
7326             return debugInfoEnabled;
7327           };
7328
7329           this.$get = [
7330                     '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
7331                     '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
7332             function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
7333                      $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
7334
7335             var Attributes = function(element, attributesToCopy) {
7336               if (attributesToCopy) {
7337                 var keys = Object.keys(attributesToCopy);
7338                 var i, l, key;
7339
7340                 for (i = 0, l = keys.length; i < l; i++) {
7341                   key = keys[i];
7342                   this[key] = attributesToCopy[key];
7343                 }
7344               } else {
7345                 this.$attr = {};
7346               }
7347
7348               this.$$element = element;
7349             };
7350
7351             Attributes.prototype = {
7352               /**
7353                * @ngdoc method
7354                * @name $compile.directive.Attributes#$normalize
7355                * @kind function
7356                *
7357                * @description
7358                * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
7359                * `data-`) to its normalized, camelCase form.
7360                *
7361                * Also there is special case for Moz prefix starting with upper case letter.
7362                *
7363                * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
7364                *
7365                * @param {string} name Name to normalize
7366                */
7367               $normalize: directiveNormalize,
7368
7369
7370               /**
7371                * @ngdoc method
7372                * @name $compile.directive.Attributes#$addClass
7373                * @kind function
7374                *
7375                * @description
7376                * Adds the CSS class value specified by the classVal parameter to the element. If animations
7377                * are enabled then an animation will be triggered for the class addition.
7378                *
7379                * @param {string} classVal The className value that will be added to the element
7380                */
7381               $addClass: function(classVal) {
7382                 if (classVal && classVal.length > 0) {
7383                   $animate.addClass(this.$$element, classVal);
7384                 }
7385               },
7386
7387               /**
7388                * @ngdoc method
7389                * @name $compile.directive.Attributes#$removeClass
7390                * @kind function
7391                *
7392                * @description
7393                * Removes the CSS class value specified by the classVal parameter from the element. If
7394                * animations are enabled then an animation will be triggered for the class removal.
7395                *
7396                * @param {string} classVal The className value that will be removed from the element
7397                */
7398               $removeClass: function(classVal) {
7399                 if (classVal && classVal.length > 0) {
7400                   $animate.removeClass(this.$$element, classVal);
7401                 }
7402               },
7403
7404               /**
7405                * @ngdoc method
7406                * @name $compile.directive.Attributes#$updateClass
7407                * @kind function
7408                *
7409                * @description
7410                * Adds and removes the appropriate CSS class values to the element based on the difference
7411                * between the new and old CSS class values (specified as newClasses and oldClasses).
7412                *
7413                * @param {string} newClasses The current CSS className value
7414                * @param {string} oldClasses The former CSS className value
7415                */
7416               $updateClass: function(newClasses, oldClasses) {
7417                 var toAdd = tokenDifference(newClasses, oldClasses);
7418                 if (toAdd && toAdd.length) {
7419                   $animate.addClass(this.$$element, toAdd);
7420                 }
7421
7422                 var toRemove = tokenDifference(oldClasses, newClasses);
7423                 if (toRemove && toRemove.length) {
7424                   $animate.removeClass(this.$$element, toRemove);
7425                 }
7426               },
7427
7428               /**
7429                * Set a normalized attribute on the element in a way such that all directives
7430                * can share the attribute. This function properly handles boolean attributes.
7431                * @param {string} key Normalized key. (ie ngAttribute)
7432                * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
7433                * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
7434                *     Defaults to true.
7435                * @param {string=} attrName Optional none normalized name. Defaults to key.
7436                */
7437               $set: function(key, value, writeAttr, attrName) {
7438                 // TODO: decide whether or not to throw an error if "class"
7439                 //is set through this function since it may cause $updateClass to
7440                 //become unstable.
7441
7442                 var node = this.$$element[0],
7443                     booleanKey = getBooleanAttrName(node, key),
7444                     aliasedKey = getAliasedAttrName(key),
7445                     observer = key,
7446                     nodeName;
7447
7448                 if (booleanKey) {
7449                   this.$$element.prop(key, value);
7450                   attrName = booleanKey;
7451                 } else if (aliasedKey) {
7452                   this[aliasedKey] = value;
7453                   observer = aliasedKey;
7454                 }
7455
7456                 this[key] = value;
7457
7458                 // translate normalized key to actual key
7459                 if (attrName) {
7460                   this.$attr[key] = attrName;
7461                 } else {
7462                   attrName = this.$attr[key];
7463                   if (!attrName) {
7464                     this.$attr[key] = attrName = snake_case(key, '-');
7465                   }
7466                 }
7467
7468                 nodeName = nodeName_(this.$$element);
7469
7470                 if ((nodeName === 'a' && key === 'href') ||
7471                     (nodeName === 'img' && key === 'src')) {
7472                   // sanitize a[href] and img[src] values
7473                   this[key] = value = $$sanitizeUri(value, key === 'src');
7474                 } else if (nodeName === 'img' && key === 'srcset') {
7475                   // sanitize img[srcset] values
7476                   var result = "";
7477
7478                   // first check if there are spaces because it's not the same pattern
7479                   var trimmedSrcset = trim(value);
7480                   //                (   999x   ,|   999w   ,|   ,|,   )
7481                   var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
7482                   var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
7483
7484                   // split srcset into tuple of uri and descriptor except for the last item
7485                   var rawUris = trimmedSrcset.split(pattern);
7486
7487                   // for each tuples
7488                   var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
7489                   for (var i = 0; i < nbrUrisWith2parts; i++) {
7490                     var innerIdx = i * 2;
7491                     // sanitize the uri
7492                     result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
7493                     // add the descriptor
7494                     result += (" " + trim(rawUris[innerIdx + 1]));
7495                   }
7496
7497                   // split the last item into uri and descriptor
7498                   var lastTuple = trim(rawUris[i * 2]).split(/\s/);
7499
7500                   // sanitize the last uri
7501                   result += $$sanitizeUri(trim(lastTuple[0]), true);
7502
7503                   // and add the last descriptor if any
7504                   if (lastTuple.length === 2) {
7505                     result += (" " + trim(lastTuple[1]));
7506                   }
7507                   this[key] = value = result;
7508                 }
7509
7510                 if (writeAttr !== false) {
7511                   if (value === null || isUndefined(value)) {
7512                     this.$$element.removeAttr(attrName);
7513                   } else {
7514                     this.$$element.attr(attrName, value);
7515                   }
7516                 }
7517
7518                 // fire observers
7519                 var $$observers = this.$$observers;
7520                 $$observers && forEach($$observers[observer], function(fn) {
7521                   try {
7522                     fn(value);
7523                   } catch (e) {
7524                     $exceptionHandler(e);
7525                   }
7526                 });
7527               },
7528
7529
7530               /**
7531                * @ngdoc method
7532                * @name $compile.directive.Attributes#$observe
7533                * @kind function
7534                *
7535                * @description
7536                * Observes an interpolated attribute.
7537                *
7538                * The observer function will be invoked once during the next `$digest` following
7539                * compilation. The observer is then invoked whenever the interpolated value
7540                * changes.
7541                *
7542                * @param {string} key Normalized key. (ie ngAttribute) .
7543                * @param {function(interpolatedValue)} fn Function that will be called whenever
7544                         the interpolated value of the attribute changes.
7545                *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
7546                * @returns {function()} Returns a deregistration function for this observer.
7547                */
7548               $observe: function(key, fn) {
7549                 var attrs = this,
7550                     $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
7551                     listeners = ($$observers[key] || ($$observers[key] = []));
7552
7553                 listeners.push(fn);
7554                 $rootScope.$evalAsync(function() {
7555                   if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
7556                     // no one registered attribute interpolation function, so lets call it manually
7557                     fn(attrs[key]);
7558                   }
7559                 });
7560
7561                 return function() {
7562                   arrayRemove(listeners, fn);
7563                 };
7564               }
7565             };
7566
7567
7568             function safeAddClass($element, className) {
7569               try {
7570                 $element.addClass(className);
7571               } catch (e) {
7572                 // ignore, since it means that we are trying to set class on
7573                 // SVG element, where class name is read-only.
7574               }
7575             }
7576
7577
7578             var startSymbol = $interpolate.startSymbol(),
7579                 endSymbol = $interpolate.endSymbol(),
7580                 denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
7581                     ? identity
7582                     : function denormalizeTemplate(template) {
7583                       return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
7584                 },
7585                 NG_ATTR_BINDING = /^ngAttr[A-Z]/;
7586             var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
7587
7588             compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
7589               var bindings = $element.data('$binding') || [];
7590
7591               if (isArray(binding)) {
7592                 bindings = bindings.concat(binding);
7593               } else {
7594                 bindings.push(binding);
7595               }
7596
7597               $element.data('$binding', bindings);
7598             } : noop;
7599
7600             compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
7601               safeAddClass($element, 'ng-binding');
7602             } : noop;
7603
7604             compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
7605               var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
7606               $element.data(dataName, scope);
7607             } : noop;
7608
7609             compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
7610               safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
7611             } : noop;
7612
7613             return compile;
7614
7615             //================================
7616
7617             function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
7618                                 previousCompileContext) {
7619               if (!($compileNodes instanceof jqLite)) {
7620                 // jquery always rewraps, whereas we need to preserve the original selector so that we can
7621                 // modify it.
7622                 $compileNodes = jqLite($compileNodes);
7623               }
7624               // We can not compile top level text elements since text nodes can be merged and we will
7625               // not be able to attach scope data to them, so we will wrap them in <span>
7626               forEach($compileNodes, function(node, index) {
7627                 if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
7628                   $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
7629                 }
7630               });
7631               var compositeLinkFn =
7632                       compileNodes($compileNodes, transcludeFn, $compileNodes,
7633                                    maxPriority, ignoreDirective, previousCompileContext);
7634               compile.$$addScopeClass($compileNodes);
7635               var namespace = null;
7636               return function publicLinkFn(scope, cloneConnectFn, options) {
7637                 assertArg(scope, 'scope');
7638
7639                 if (previousCompileContext && previousCompileContext.needsNewScope) {
7640                   // A parent directive did a replace and a directive on this element asked
7641                   // for transclusion, which caused us to lose a layer of element on which
7642                   // we could hold the new transclusion scope, so we will create it manually
7643                   // here.
7644                   scope = scope.$parent.$new();
7645                 }
7646
7647                 options = options || {};
7648                 var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
7649                   transcludeControllers = options.transcludeControllers,
7650                   futureParentElement = options.futureParentElement;
7651
7652                 // When `parentBoundTranscludeFn` is passed, it is a
7653                 // `controllersBoundTransclude` function (it was previously passed
7654                 // as `transclude` to directive.link) so we must unwrap it to get
7655                 // its `boundTranscludeFn`
7656                 if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
7657                   parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
7658                 }
7659
7660                 if (!namespace) {
7661                   namespace = detectNamespaceForChildElements(futureParentElement);
7662                 }
7663                 var $linkNode;
7664                 if (namespace !== 'html') {
7665                   // When using a directive with replace:true and templateUrl the $compileNodes
7666                   // (or a child element inside of them)
7667                   // might change, so we need to recreate the namespace adapted compileNodes
7668                   // for call to the link function.
7669                   // Note: This will already clone the nodes...
7670                   $linkNode = jqLite(
7671                     wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
7672                   );
7673                 } else if (cloneConnectFn) {
7674                   // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
7675                   // and sometimes changes the structure of the DOM.
7676                   $linkNode = JQLitePrototype.clone.call($compileNodes);
7677                 } else {
7678                   $linkNode = $compileNodes;
7679                 }
7680
7681                 if (transcludeControllers) {
7682                   for (var controllerName in transcludeControllers) {
7683                     $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
7684                   }
7685                 }
7686
7687                 compile.$$addScopeInfo($linkNode, scope);
7688
7689                 if (cloneConnectFn) cloneConnectFn($linkNode, scope);
7690                 if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
7691                 return $linkNode;
7692               };
7693             }
7694
7695             function detectNamespaceForChildElements(parentElement) {
7696               // TODO: Make this detect MathML as well...
7697               var node = parentElement && parentElement[0];
7698               if (!node) {
7699                 return 'html';
7700               } else {
7701                 return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
7702               }
7703             }
7704
7705             /**
7706              * Compile function matches each node in nodeList against the directives. Once all directives
7707              * for a particular node are collected their compile functions are executed. The compile
7708              * functions return values - the linking functions - are combined into a composite linking
7709              * function, which is the a linking function for the node.
7710              *
7711              * @param {NodeList} nodeList an array of nodes or NodeList to compile
7712              * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7713              *        scope argument is auto-generated to the new child of the transcluded parent scope.
7714              * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
7715              *        the rootElement must be set the jqLite collection of the compile root. This is
7716              *        needed so that the jqLite collection items can be replaced with widgets.
7717              * @param {number=} maxPriority Max directive priority.
7718              * @returns {Function} A composite linking function of all of the matched directives or null.
7719              */
7720             function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
7721                                     previousCompileContext) {
7722               var linkFns = [],
7723                   attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
7724
7725               for (var i = 0; i < nodeList.length; i++) {
7726                 attrs = new Attributes();
7727
7728                 // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
7729                 directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
7730                                                 ignoreDirective);
7731
7732                 nodeLinkFn = (directives.length)
7733                     ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
7734                                               null, [], [], previousCompileContext)
7735                     : null;
7736
7737                 if (nodeLinkFn && nodeLinkFn.scope) {
7738                   compile.$$addScopeClass(attrs.$$element);
7739                 }
7740
7741                 childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
7742                               !(childNodes = nodeList[i].childNodes) ||
7743                               !childNodes.length)
7744                     ? null
7745                     : compileNodes(childNodes,
7746                          nodeLinkFn ? (
7747                           (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
7748                              && nodeLinkFn.transclude) : transcludeFn);
7749
7750                 if (nodeLinkFn || childLinkFn) {
7751                   linkFns.push(i, nodeLinkFn, childLinkFn);
7752                   linkFnFound = true;
7753                   nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
7754                 }
7755
7756                 //use the previous context only for the first element in the virtual group
7757                 previousCompileContext = null;
7758               }
7759
7760               // return a linking function if we have found anything, null otherwise
7761               return linkFnFound ? compositeLinkFn : null;
7762
7763               function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
7764                 var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
7765                 var stableNodeList;
7766
7767
7768                 if (nodeLinkFnFound) {
7769                   // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
7770                   // offsets don't get screwed up
7771                   var nodeListLength = nodeList.length;
7772                   stableNodeList = new Array(nodeListLength);
7773
7774                   // create a sparse array by only copying the elements which have a linkFn
7775                   for (i = 0; i < linkFns.length; i+=3) {
7776                     idx = linkFns[i];
7777                     stableNodeList[idx] = nodeList[idx];
7778                   }
7779                 } else {
7780                   stableNodeList = nodeList;
7781                 }
7782
7783                 for (i = 0, ii = linkFns.length; i < ii;) {
7784                   node = stableNodeList[linkFns[i++]];
7785                   nodeLinkFn = linkFns[i++];
7786                   childLinkFn = linkFns[i++];
7787
7788                   if (nodeLinkFn) {
7789                     if (nodeLinkFn.scope) {
7790                       childScope = scope.$new();
7791                       compile.$$addScopeInfo(jqLite(node), childScope);
7792                     } else {
7793                       childScope = scope;
7794                     }
7795
7796                     if (nodeLinkFn.transcludeOnThisElement) {
7797                       childBoundTranscludeFn = createBoundTranscludeFn(
7798                           scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
7799
7800                     } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
7801                       childBoundTranscludeFn = parentBoundTranscludeFn;
7802
7803                     } else if (!parentBoundTranscludeFn && transcludeFn) {
7804                       childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
7805
7806                     } else {
7807                       childBoundTranscludeFn = null;
7808                     }
7809
7810                     nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
7811
7812                   } else if (childLinkFn) {
7813                     childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
7814                   }
7815                 }
7816               }
7817             }
7818
7819             function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
7820
7821               var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
7822
7823                 if (!transcludedScope) {
7824                   transcludedScope = scope.$new(false, containingScope);
7825                   transcludedScope.$$transcluded = true;
7826                 }
7827
7828                 return transcludeFn(transcludedScope, cloneFn, {
7829                   parentBoundTranscludeFn: previousBoundTranscludeFn,
7830                   transcludeControllers: controllers,
7831                   futureParentElement: futureParentElement
7832                 });
7833               };
7834
7835               return boundTranscludeFn;
7836             }
7837
7838             /**
7839              * Looks for directives on the given node and adds them to the directive collection which is
7840              * sorted.
7841              *
7842              * @param node Node to search.
7843              * @param directives An array to which the directives are added to. This array is sorted before
7844              *        the function returns.
7845              * @param attrs The shared attrs object which is used to populate the normalized attributes.
7846              * @param {number=} maxPriority Max directive priority.
7847              */
7848             function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
7849               var nodeType = node.nodeType,
7850                   attrsMap = attrs.$attr,
7851                   match,
7852                   className;
7853
7854               switch (nodeType) {
7855                 case NODE_TYPE_ELEMENT: /* Element */
7856                   // use the node name: <directive>
7857                   addDirective(directives,
7858                       directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
7859
7860                   // iterate over the attributes
7861                   for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
7862                            j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
7863                     var attrStartName = false;
7864                     var attrEndName = false;
7865
7866                     attr = nAttrs[j];
7867                     name = attr.name;
7868                     value = trim(attr.value);
7869
7870                     // support ngAttr attribute binding
7871                     ngAttrName = directiveNormalize(name);
7872                     if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
7873                       name = name.replace(PREFIX_REGEXP, '')
7874                         .substr(8).replace(/_(.)/g, function(match, letter) {
7875                           return letter.toUpperCase();
7876                         });
7877                     }
7878
7879                     var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
7880                     if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
7881                       attrStartName = name;
7882                       attrEndName = name.substr(0, name.length - 5) + 'end';
7883                       name = name.substr(0, name.length - 6);
7884                     }
7885
7886                     nName = directiveNormalize(name.toLowerCase());
7887                     attrsMap[nName] = name;
7888                     if (isNgAttr || !attrs.hasOwnProperty(nName)) {
7889                         attrs[nName] = value;
7890                         if (getBooleanAttrName(node, nName)) {
7891                           attrs[nName] = true; // presence means true
7892                         }
7893                     }
7894                     addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
7895                     addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
7896                                   attrEndName);
7897                   }
7898
7899                   // use class as directive
7900                   className = node.className;
7901                   if (isObject(className)) {
7902                       // Maybe SVGAnimatedString
7903                       className = className.animVal;
7904                   }
7905                   if (isString(className) && className !== '') {
7906                     while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
7907                       nName = directiveNormalize(match[2]);
7908                       if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
7909                         attrs[nName] = trim(match[3]);
7910                       }
7911                       className = className.substr(match.index + match[0].length);
7912                     }
7913                   }
7914                   break;
7915                 case NODE_TYPE_TEXT: /* Text Node */
7916                   if (msie === 11) {
7917                     // Workaround for #11781
7918                     while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
7919                       node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
7920                       node.parentNode.removeChild(node.nextSibling);
7921                     }
7922                   }
7923                   addTextInterpolateDirective(directives, node.nodeValue);
7924                   break;
7925                 case NODE_TYPE_COMMENT: /* Comment */
7926                   try {
7927                     match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
7928                     if (match) {
7929                       nName = directiveNormalize(match[1]);
7930                       if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
7931                         attrs[nName] = trim(match[2]);
7932                       }
7933                     }
7934                   } catch (e) {
7935                     // turns out that under some circumstances IE9 throws errors when one attempts to read
7936                     // comment's node value.
7937                     // Just ignore it and continue. (Can't seem to reproduce in test case.)
7938                   }
7939                   break;
7940               }
7941
7942               directives.sort(byPriority);
7943               return directives;
7944             }
7945
7946             /**
7947              * Given a node with an directive-start it collects all of the siblings until it finds
7948              * directive-end.
7949              * @param node
7950              * @param attrStart
7951              * @param attrEnd
7952              * @returns {*}
7953              */
7954             function groupScan(node, attrStart, attrEnd) {
7955               var nodes = [];
7956               var depth = 0;
7957               if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
7958                 do {
7959                   if (!node) {
7960                     throw $compileMinErr('uterdir',
7961                               "Unterminated attribute, found '{0}' but no matching '{1}' found.",
7962                               attrStart, attrEnd);
7963                   }
7964                   if (node.nodeType == NODE_TYPE_ELEMENT) {
7965                     if (node.hasAttribute(attrStart)) depth++;
7966                     if (node.hasAttribute(attrEnd)) depth--;
7967                   }
7968                   nodes.push(node);
7969                   node = node.nextSibling;
7970                 } while (depth > 0);
7971               } else {
7972                 nodes.push(node);
7973               }
7974
7975               return jqLite(nodes);
7976             }
7977
7978             /**
7979              * Wrapper for linking function which converts normal linking function into a grouped
7980              * linking function.
7981              * @param linkFn
7982              * @param attrStart
7983              * @param attrEnd
7984              * @returns {Function}
7985              */
7986             function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
7987               return function(scope, element, attrs, controllers, transcludeFn) {
7988                 element = groupScan(element[0], attrStart, attrEnd);
7989                 return linkFn(scope, element, attrs, controllers, transcludeFn);
7990               };
7991             }
7992
7993             /**
7994              * Once the directives have been collected, their compile functions are executed. This method
7995              * is responsible for inlining directive templates as well as terminating the application
7996              * of the directives if the terminal directive has been reached.
7997              *
7998              * @param {Array} directives Array of collected directives to execute their compile function.
7999              *        this needs to be pre-sorted by priority order.
8000              * @param {Node} compileNode The raw DOM node to apply the compile functions to
8001              * @param {Object} templateAttrs The shared attribute function
8002              * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
8003              *                                                  scope argument is auto-generated to the new
8004              *                                                  child of the transcluded parent scope.
8005              * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
8006              *                              argument has the root jqLite array so that we can replace nodes
8007              *                              on it.
8008              * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
8009              *                                           compiling the transclusion.
8010              * @param {Array.<Function>} preLinkFns
8011              * @param {Array.<Function>} postLinkFns
8012              * @param {Object} previousCompileContext Context used for previous compilation of the current
8013              *                                        node
8014              * @returns {Function} linkFn
8015              */
8016             function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
8017                                            jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
8018                                            previousCompileContext) {
8019               previousCompileContext = previousCompileContext || {};
8020
8021               var terminalPriority = -Number.MAX_VALUE,
8022                   newScopeDirective = previousCompileContext.newScopeDirective,
8023                   controllerDirectives = previousCompileContext.controllerDirectives,
8024                   newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
8025                   templateDirective = previousCompileContext.templateDirective,
8026                   nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
8027                   hasTranscludeDirective = false,
8028                   hasTemplate = false,
8029                   hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
8030                   $compileNode = templateAttrs.$$element = jqLite(compileNode),
8031                   directive,
8032                   directiveName,
8033                   $template,
8034                   replaceDirective = originalReplaceDirective,
8035                   childTranscludeFn = transcludeFn,
8036                   linkFn,
8037                   directiveValue;
8038
8039               // executes all directives on the current element
8040               for (var i = 0, ii = directives.length; i < ii; i++) {
8041                 directive = directives[i];
8042                 var attrStart = directive.$$start;
8043                 var attrEnd = directive.$$end;
8044
8045                 // collect multiblock sections
8046                 if (attrStart) {
8047                   $compileNode = groupScan(compileNode, attrStart, attrEnd);
8048                 }
8049                 $template = undefined;
8050
8051                 if (terminalPriority > directive.priority) {
8052                   break; // prevent further processing of directives
8053                 }
8054
8055                 if (directiveValue = directive.scope) {
8056
8057                   // skip the check for directives with async templates, we'll check the derived sync
8058                   // directive when the template arrives
8059                   if (!directive.templateUrl) {
8060                     if (isObject(directiveValue)) {
8061                       // This directive is trying to add an isolated scope.
8062                       // Check that there is no scope of any kind already
8063                       assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
8064                                         directive, $compileNode);
8065                       newIsolateScopeDirective = directive;
8066                     } else {
8067                       // This directive is trying to add a child scope.
8068                       // Check that there is no isolated scope already
8069                       assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
8070                                         $compileNode);
8071                     }
8072                   }
8073
8074                   newScopeDirective = newScopeDirective || directive;
8075                 }
8076
8077                 directiveName = directive.name;
8078
8079                 if (!directive.templateUrl && directive.controller) {
8080                   directiveValue = directive.controller;
8081                   controllerDirectives = controllerDirectives || createMap();
8082                   assertNoDuplicate("'" + directiveName + "' controller",
8083                       controllerDirectives[directiveName], directive, $compileNode);
8084                   controllerDirectives[directiveName] = directive;
8085                 }
8086
8087                 if (directiveValue = directive.transclude) {
8088                   hasTranscludeDirective = true;
8089
8090                   // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
8091                   // This option should only be used by directives that know how to safely handle element transclusion,
8092                   // where the transcluded nodes are added or replaced after linking.
8093                   if (!directive.$$tlb) {
8094                     assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
8095                     nonTlbTranscludeDirective = directive;
8096                   }
8097
8098                   if (directiveValue == 'element') {
8099                     hasElementTranscludeDirective = true;
8100                     terminalPriority = directive.priority;
8101                     $template = $compileNode;
8102                     $compileNode = templateAttrs.$$element =
8103                         jqLite(document.createComment(' ' + directiveName + ': ' +
8104                                                       templateAttrs[directiveName] + ' '));
8105                     compileNode = $compileNode[0];
8106                     replaceWith(jqCollection, sliceArgs($template), compileNode);
8107
8108                     childTranscludeFn = compile($template, transcludeFn, terminalPriority,
8109                                                 replaceDirective && replaceDirective.name, {
8110                                                   // Don't pass in:
8111                                                   // - controllerDirectives - otherwise we'll create duplicates controllers
8112                                                   // - newIsolateScopeDirective or templateDirective - combining templates with
8113                                                   //   element transclusion doesn't make sense.
8114                                                   //
8115                                                   // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
8116                                                   // on the same element more than once.
8117                                                   nonTlbTranscludeDirective: nonTlbTranscludeDirective
8118                                                 });
8119                   } else {
8120                     $template = jqLite(jqLiteClone(compileNode)).contents();
8121                     $compileNode.empty(); // clear contents
8122                     childTranscludeFn = compile($template, transcludeFn, undefined,
8123                         undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
8124                   }
8125                 }
8126
8127                 if (directive.template) {
8128                   hasTemplate = true;
8129                   assertNoDuplicate('template', templateDirective, directive, $compileNode);
8130                   templateDirective = directive;
8131
8132                   directiveValue = (isFunction(directive.template))
8133                       ? directive.template($compileNode, templateAttrs)
8134                       : directive.template;
8135
8136                   directiveValue = denormalizeTemplate(directiveValue);
8137
8138                   if (directive.replace) {
8139                     replaceDirective = directive;
8140                     if (jqLiteIsTextNode(directiveValue)) {
8141                       $template = [];
8142                     } else {
8143                       $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
8144                     }
8145                     compileNode = $template[0];
8146
8147                     if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8148                       throw $compileMinErr('tplrt',
8149                           "Template for directive '{0}' must have exactly one root element. {1}",
8150                           directiveName, '');
8151                     }
8152
8153                     replaceWith(jqCollection, $compileNode, compileNode);
8154
8155                     var newTemplateAttrs = {$attr: {}};
8156
8157                     // combine directives from the original node and from the template:
8158                     // - take the array of directives for this element
8159                     // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
8160                     // - collect directives from the template and sort them by priority
8161                     // - combine directives as: processed + template + unprocessed
8162                     var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
8163                     var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
8164
8165                     if (newIsolateScopeDirective || newScopeDirective) {
8166                       // The original directive caused the current element to be replaced but this element
8167                       // also needs to have a new scope, so we need to tell the template directives
8168                       // that they would need to get their scope from further up, if they require transclusion
8169                       markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
8170                     }
8171                     directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
8172                     mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
8173
8174                     ii = directives.length;
8175                   } else {
8176                     $compileNode.html(directiveValue);
8177                   }
8178                 }
8179
8180                 if (directive.templateUrl) {
8181                   hasTemplate = true;
8182                   assertNoDuplicate('template', templateDirective, directive, $compileNode);
8183                   templateDirective = directive;
8184
8185                   if (directive.replace) {
8186                     replaceDirective = directive;
8187                   }
8188
8189                   nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
8190                       templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
8191                         controllerDirectives: controllerDirectives,
8192                         newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
8193                         newIsolateScopeDirective: newIsolateScopeDirective,
8194                         templateDirective: templateDirective,
8195                         nonTlbTranscludeDirective: nonTlbTranscludeDirective
8196                       });
8197                   ii = directives.length;
8198                 } else if (directive.compile) {
8199                   try {
8200                     linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
8201                     if (isFunction(linkFn)) {
8202                       addLinkFns(null, linkFn, attrStart, attrEnd);
8203                     } else if (linkFn) {
8204                       addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
8205                     }
8206                   } catch (e) {
8207                     $exceptionHandler(e, startingTag($compileNode));
8208                   }
8209                 }
8210
8211                 if (directive.terminal) {
8212                   nodeLinkFn.terminal = true;
8213                   terminalPriority = Math.max(terminalPriority, directive.priority);
8214                 }
8215
8216               }
8217
8218               nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
8219               nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
8220               nodeLinkFn.templateOnThisElement = hasTemplate;
8221               nodeLinkFn.transclude = childTranscludeFn;
8222
8223               previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
8224
8225               // might be normal or delayed nodeLinkFn depending on if templateUrl is present
8226               return nodeLinkFn;
8227
8228               ////////////////////
8229
8230               function addLinkFns(pre, post, attrStart, attrEnd) {
8231                 if (pre) {
8232                   if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
8233                   pre.require = directive.require;
8234                   pre.directiveName = directiveName;
8235                   if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
8236                     pre = cloneAndAnnotateFn(pre, {isolateScope: true});
8237                   }
8238                   preLinkFns.push(pre);
8239                 }
8240                 if (post) {
8241                   if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
8242                   post.require = directive.require;
8243                   post.directiveName = directiveName;
8244                   if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
8245                     post = cloneAndAnnotateFn(post, {isolateScope: true});
8246                   }
8247                   postLinkFns.push(post);
8248                 }
8249               }
8250
8251
8252               function getControllers(directiveName, require, $element, elementControllers) {
8253                 var value;
8254
8255                 if (isString(require)) {
8256                   var match = require.match(REQUIRE_PREFIX_REGEXP);
8257                   var name = require.substring(match[0].length);
8258                   var inheritType = match[1] || match[3];
8259                   var optional = match[2] === '?';
8260
8261                   //If only parents then start at the parent element
8262                   if (inheritType === '^^') {
8263                     $element = $element.parent();
8264                   //Otherwise attempt getting the controller from elementControllers in case
8265                   //the element is transcluded (and has no data) and to avoid .data if possible
8266                   } else {
8267                     value = elementControllers && elementControllers[name];
8268                     value = value && value.instance;
8269                   }
8270
8271                   if (!value) {
8272                     var dataName = '$' + name + 'Controller';
8273                     value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
8274                   }
8275
8276                   if (!value && !optional) {
8277                     throw $compileMinErr('ctreq',
8278                         "Controller '{0}', required by directive '{1}', can't be found!",
8279                         name, directiveName);
8280                   }
8281                 } else if (isArray(require)) {
8282                   value = [];
8283                   for (var i = 0, ii = require.length; i < ii; i++) {
8284                     value[i] = getControllers(directiveName, require[i], $element, elementControllers);
8285                   }
8286                 }
8287
8288                 return value || null;
8289               }
8290
8291               function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
8292                 var elementControllers = createMap();
8293                 for (var controllerKey in controllerDirectives) {
8294                   var directive = controllerDirectives[controllerKey];
8295                   var locals = {
8296                     $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
8297                     $element: $element,
8298                     $attrs: attrs,
8299                     $transclude: transcludeFn
8300                   };
8301
8302                   var controller = directive.controller;
8303                   if (controller == '@') {
8304                     controller = attrs[directive.name];
8305                   }
8306
8307                   var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
8308
8309                   // For directives with element transclusion the element is a comment,
8310                   // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
8311                   // clean up (http://bugs.jquery.com/ticket/8335).
8312                   // Instead, we save the controllers for the element in a local hash and attach to .data
8313                   // later, once we have the actual element.
8314                   elementControllers[directive.name] = controllerInstance;
8315                   if (!hasElementTranscludeDirective) {
8316                     $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
8317                   }
8318                 }
8319                 return elementControllers;
8320               }
8321
8322               function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
8323                 var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8324                     attrs, removeScopeBindingWatches, removeControllerBindingWatches;
8325
8326                 if (compileNode === linkNode) {
8327                   attrs = templateAttrs;
8328                   $element = templateAttrs.$$element;
8329                 } else {
8330                   $element = jqLite(linkNode);
8331                   attrs = new Attributes($element, templateAttrs);
8332                 }
8333
8334                 controllerScope = scope;
8335                 if (newIsolateScopeDirective) {
8336                   isolateScope = scope.$new(true);
8337                 } else if (newScopeDirective) {
8338                   controllerScope = scope.$parent;
8339                 }
8340
8341                 if (boundTranscludeFn) {
8342                   // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
8343                   // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
8344                   transcludeFn = controllersBoundTransclude;
8345                   transcludeFn.$$boundTransclude = boundTranscludeFn;
8346                 }
8347
8348                 if (controllerDirectives) {
8349                   elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
8350                 }
8351
8352                 if (newIsolateScopeDirective) {
8353                   // Initialize isolate scope bindings for new isolate scope directive.
8354                   compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
8355                       templateDirective === newIsolateScopeDirective.$$originalDirective)));
8356                   compile.$$addScopeClass($element, true);
8357                   isolateScope.$$isolateBindings =
8358                       newIsolateScopeDirective.$$isolateBindings;
8359                   removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
8360                                                 isolateScope.$$isolateBindings,
8361                                                 newIsolateScopeDirective);
8362                   if (removeScopeBindingWatches) {
8363                     isolateScope.$on('$destroy', removeScopeBindingWatches);
8364                   }
8365                 }
8366
8367                 // Initialize bindToController bindings
8368                 for (var name in elementControllers) {
8369                   var controllerDirective = controllerDirectives[name];
8370                   var controller = elementControllers[name];
8371                   var bindings = controllerDirective.$$bindings.bindToController;
8372
8373                   if (controller.identifier && bindings) {
8374                     removeControllerBindingWatches =
8375                       initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8376                   }
8377
8378                   var controllerResult = controller();
8379                   if (controllerResult !== controller.instance) {
8380                     // If the controller constructor has a return value, overwrite the instance
8381                     // from setupControllers
8382                     controller.instance = controllerResult;
8383                     $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
8384                     removeControllerBindingWatches && removeControllerBindingWatches();
8385                     removeControllerBindingWatches =
8386                       initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8387                   }
8388                 }
8389
8390                 // PRELINKING
8391                 for (i = 0, ii = preLinkFns.length; i < ii; i++) {
8392                   linkFn = preLinkFns[i];
8393                   invokeLinkFn(linkFn,
8394                       linkFn.isolateScope ? isolateScope : scope,
8395                       $element,
8396                       attrs,
8397                       linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8398                       transcludeFn
8399                   );
8400                 }
8401
8402                 // RECURSION
8403                 // We only pass the isolate scope, if the isolate directive has a template,
8404                 // otherwise the child elements do not belong to the isolate directive.
8405                 var scopeToChild = scope;
8406                 if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
8407                   scopeToChild = isolateScope;
8408                 }
8409                 childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
8410
8411                 // POSTLINKING
8412                 for (i = postLinkFns.length - 1; i >= 0; i--) {
8413                   linkFn = postLinkFns[i];
8414                   invokeLinkFn(linkFn,
8415                       linkFn.isolateScope ? isolateScope : scope,
8416                       $element,
8417                       attrs,
8418                       linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8419                       transcludeFn
8420                   );
8421                 }
8422
8423                 // This is the function that is injected as `$transclude`.
8424                 // Note: all arguments are optional!
8425                 function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
8426                   var transcludeControllers;
8427
8428                   // No scope passed in:
8429                   if (!isScope(scope)) {
8430                     futureParentElement = cloneAttachFn;
8431                     cloneAttachFn = scope;
8432                     scope = undefined;
8433                   }
8434
8435                   if (hasElementTranscludeDirective) {
8436                     transcludeControllers = elementControllers;
8437                   }
8438                   if (!futureParentElement) {
8439                     futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
8440                   }
8441                   return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
8442                 }
8443               }
8444             }
8445
8446             // Depending upon the context in which a directive finds itself it might need to have a new isolated
8447             // or child scope created. For instance:
8448             // * if the directive has been pulled into a template because another directive with a higher priority
8449             // asked for element transclusion
8450             // * if the directive itself asks for transclusion but it is at the root of a template and the original
8451             // element was replaced. See https://github.com/angular/angular.js/issues/12936
8452             function markDirectiveScope(directives, isolateScope, newScope) {
8453               for (var j = 0, jj = directives.length; j < jj; j++) {
8454                 directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
8455               }
8456             }
8457
8458             /**
8459              * looks up the directive and decorates it with exception handling and proper parameters. We
8460              * call this the boundDirective.
8461              *
8462              * @param {string} name name of the directive to look up.
8463              * @param {string} location The directive must be found in specific format.
8464              *   String containing any of theses characters:
8465              *
8466              *   * `E`: element name
8467              *   * `A': attribute
8468              *   * `C`: class
8469              *   * `M`: comment
8470              * @returns {boolean} true if directive was added.
8471              */
8472             function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
8473                                   endAttrName) {
8474               if (name === ignoreDirective) return null;
8475               var match = null;
8476               if (hasDirectives.hasOwnProperty(name)) {
8477                 for (var directive, directives = $injector.get(name + Suffix),
8478                     i = 0, ii = directives.length; i < ii; i++) {
8479                   try {
8480                     directive = directives[i];
8481                     if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
8482                          directive.restrict.indexOf(location) != -1) {
8483                       if (startAttrName) {
8484                         directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
8485                       }
8486                       tDirectives.push(directive);
8487                       match = directive;
8488                     }
8489                   } catch (e) { $exceptionHandler(e); }
8490                 }
8491               }
8492               return match;
8493             }
8494
8495
8496             /**
8497              * looks up the directive and returns true if it is a multi-element directive,
8498              * and therefore requires DOM nodes between -start and -end markers to be grouped
8499              * together.
8500              *
8501              * @param {string} name name of the directive to look up.
8502              * @returns true if directive was registered as multi-element.
8503              */
8504             function directiveIsMultiElement(name) {
8505               if (hasDirectives.hasOwnProperty(name)) {
8506                 for (var directive, directives = $injector.get(name + Suffix),
8507                     i = 0, ii = directives.length; i < ii; i++) {
8508                   directive = directives[i];
8509                   if (directive.multiElement) {
8510                     return true;
8511                   }
8512                 }
8513               }
8514               return false;
8515             }
8516
8517             /**
8518              * When the element is replaced with HTML template then the new attributes
8519              * on the template need to be merged with the existing attributes in the DOM.
8520              * The desired effect is to have both of the attributes present.
8521              *
8522              * @param {object} dst destination attributes (original DOM)
8523              * @param {object} src source attributes (from the directive template)
8524              */
8525             function mergeTemplateAttributes(dst, src) {
8526               var srcAttr = src.$attr,
8527                   dstAttr = dst.$attr,
8528                   $element = dst.$$element;
8529
8530               // reapply the old attributes to the new element
8531               forEach(dst, function(value, key) {
8532                 if (key.charAt(0) != '$') {
8533                   if (src[key] && src[key] !== value) {
8534                     value += (key === 'style' ? ';' : ' ') + src[key];
8535                   }
8536                   dst.$set(key, value, true, srcAttr[key]);
8537                 }
8538               });
8539
8540               // copy the new attributes on the old attrs object
8541               forEach(src, function(value, key) {
8542                 if (key == 'class') {
8543                   safeAddClass($element, value);
8544                   dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
8545                 } else if (key == 'style') {
8546                   $element.attr('style', $element.attr('style') + ';' + value);
8547                   dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
8548                   // `dst` will never contain hasOwnProperty as DOM parser won't let it.
8549                   // You will get an "InvalidCharacterError: DOM Exception 5" error if you
8550                   // have an attribute like "has-own-property" or "data-has-own-property", etc.
8551                 } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
8552                   dst[key] = value;
8553                   dstAttr[key] = srcAttr[key];
8554                 }
8555               });
8556             }
8557
8558
8559             function compileTemplateUrl(directives, $compileNode, tAttrs,
8560                 $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
8561               var linkQueue = [],
8562                   afterTemplateNodeLinkFn,
8563                   afterTemplateChildLinkFn,
8564                   beforeTemplateCompileNode = $compileNode[0],
8565                   origAsyncDirective = directives.shift(),
8566                   derivedSyncDirective = inherit(origAsyncDirective, {
8567                     templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
8568                   }),
8569                   templateUrl = (isFunction(origAsyncDirective.templateUrl))
8570                       ? origAsyncDirective.templateUrl($compileNode, tAttrs)
8571                       : origAsyncDirective.templateUrl,
8572                   templateNamespace = origAsyncDirective.templateNamespace;
8573
8574               $compileNode.empty();
8575
8576               $templateRequest(templateUrl)
8577                 .then(function(content) {
8578                   var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
8579
8580                   content = denormalizeTemplate(content);
8581
8582                   if (origAsyncDirective.replace) {
8583                     if (jqLiteIsTextNode(content)) {
8584                       $template = [];
8585                     } else {
8586                       $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
8587                     }
8588                     compileNode = $template[0];
8589
8590                     if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8591                       throw $compileMinErr('tplrt',
8592                           "Template for directive '{0}' must have exactly one root element. {1}",
8593                           origAsyncDirective.name, templateUrl);
8594                     }
8595
8596                     tempTemplateAttrs = {$attr: {}};
8597                     replaceWith($rootElement, $compileNode, compileNode);
8598                     var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
8599
8600                     if (isObject(origAsyncDirective.scope)) {
8601                       // the original directive that caused the template to be loaded async required
8602                       // an isolate scope
8603                       markDirectiveScope(templateDirectives, true);
8604                     }
8605                     directives = templateDirectives.concat(directives);
8606                     mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
8607                   } else {
8608                     compileNode = beforeTemplateCompileNode;
8609                     $compileNode.html(content);
8610                   }
8611
8612                   directives.unshift(derivedSyncDirective);
8613
8614                   afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
8615                       childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
8616                       previousCompileContext);
8617                   forEach($rootElement, function(node, i) {
8618                     if (node == compileNode) {
8619                       $rootElement[i] = $compileNode[0];
8620                     }
8621                   });
8622                   afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
8623
8624                   while (linkQueue.length) {
8625                     var scope = linkQueue.shift(),
8626                         beforeTemplateLinkNode = linkQueue.shift(),
8627                         linkRootElement = linkQueue.shift(),
8628                         boundTranscludeFn = linkQueue.shift(),
8629                         linkNode = $compileNode[0];
8630
8631                     if (scope.$$destroyed) continue;
8632
8633                     if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
8634                       var oldClasses = beforeTemplateLinkNode.className;
8635
8636                       if (!(previousCompileContext.hasElementTranscludeDirective &&
8637                           origAsyncDirective.replace)) {
8638                         // it was cloned therefore we have to clone as well.
8639                         linkNode = jqLiteClone(compileNode);
8640                       }
8641                       replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
8642
8643                       // Copy in CSS classes from original node
8644                       safeAddClass(jqLite(linkNode), oldClasses);
8645                     }
8646                     if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8647                       childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8648                     } else {
8649                       childBoundTranscludeFn = boundTranscludeFn;
8650                     }
8651                     afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
8652                       childBoundTranscludeFn);
8653                   }
8654                   linkQueue = null;
8655                 });
8656
8657               return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
8658                 var childBoundTranscludeFn = boundTranscludeFn;
8659                 if (scope.$$destroyed) return;
8660                 if (linkQueue) {
8661                   linkQueue.push(scope,
8662                                  node,
8663                                  rootElement,
8664                                  childBoundTranscludeFn);
8665                 } else {
8666                   if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8667                     childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8668                   }
8669                   afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
8670                 }
8671               };
8672             }
8673
8674
8675             /**
8676              * Sorting function for bound directives.
8677              */
8678             function byPriority(a, b) {
8679               var diff = b.priority - a.priority;
8680               if (diff !== 0) return diff;
8681               if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
8682               return a.index - b.index;
8683             }
8684
8685             function assertNoDuplicate(what, previousDirective, directive, element) {
8686
8687               function wrapModuleNameIfDefined(moduleName) {
8688                 return moduleName ?
8689                   (' (module: ' + moduleName + ')') :
8690                   '';
8691               }
8692
8693               if (previousDirective) {
8694                 throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
8695                     previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
8696                     directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
8697               }
8698             }
8699
8700
8701             function addTextInterpolateDirective(directives, text) {
8702               var interpolateFn = $interpolate(text, true);
8703               if (interpolateFn) {
8704                 directives.push({
8705                   priority: 0,
8706                   compile: function textInterpolateCompileFn(templateNode) {
8707                     var templateNodeParent = templateNode.parent(),
8708                         hasCompileParent = !!templateNodeParent.length;
8709
8710                     // When transcluding a template that has bindings in the root
8711                     // we don't have a parent and thus need to add the class during linking fn.
8712                     if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
8713
8714                     return function textInterpolateLinkFn(scope, node) {
8715                       var parent = node.parent();
8716                       if (!hasCompileParent) compile.$$addBindingClass(parent);
8717                       compile.$$addBindingInfo(parent, interpolateFn.expressions);
8718                       scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
8719                         node[0].nodeValue = value;
8720                       });
8721                     };
8722                   }
8723                 });
8724               }
8725             }
8726
8727
8728             function wrapTemplate(type, template) {
8729               type = lowercase(type || 'html');
8730               switch (type) {
8731               case 'svg':
8732               case 'math':
8733                 var wrapper = document.createElement('div');
8734                 wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
8735                 return wrapper.childNodes[0].childNodes;
8736               default:
8737                 return template;
8738               }
8739             }
8740
8741
8742             function getTrustedContext(node, attrNormalizedName) {
8743               if (attrNormalizedName == "srcdoc") {
8744                 return $sce.HTML;
8745               }
8746               var tag = nodeName_(node);
8747               // maction[xlink:href] can source SVG.  It's not limited to <maction>.
8748               if (attrNormalizedName == "xlinkHref" ||
8749                   (tag == "form" && attrNormalizedName == "action") ||
8750                   (tag != "img" && (attrNormalizedName == "src" ||
8751                                     attrNormalizedName == "ngSrc"))) {
8752                 return $sce.RESOURCE_URL;
8753               }
8754             }
8755
8756
8757             function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
8758               var trustedContext = getTrustedContext(node, name);
8759               allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
8760
8761               var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
8762
8763               // no interpolation found -> ignore
8764               if (!interpolateFn) return;
8765
8766
8767               if (name === "multiple" && nodeName_(node) === "select") {
8768                 throw $compileMinErr("selmulti",
8769                     "Binding to the 'multiple' attribute is not supported. Element: {0}",
8770                     startingTag(node));
8771               }
8772
8773               directives.push({
8774                 priority: 100,
8775                 compile: function() {
8776                     return {
8777                       pre: function attrInterpolatePreLinkFn(scope, element, attr) {
8778                         var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
8779
8780                         if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
8781                           throw $compileMinErr('nodomevents',
8782                               "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
8783                                   "ng- versions (such as ng-click instead of onclick) instead.");
8784                         }
8785
8786                         // If the attribute has changed since last $interpolate()ed
8787                         var newValue = attr[name];
8788                         if (newValue !== value) {
8789                           // we need to interpolate again since the attribute value has been updated
8790                           // (e.g. by another directive's compile function)
8791                           // ensure unset/empty values make interpolateFn falsy
8792                           interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
8793                           value = newValue;
8794                         }
8795
8796                         // if attribute was updated so that there is no interpolation going on we don't want to
8797                         // register any observers
8798                         if (!interpolateFn) return;
8799
8800                         // initialize attr object so that it's ready in case we need the value for isolate
8801                         // scope initialization, otherwise the value would not be available from isolate
8802                         // directive's linking fn during linking phase
8803                         attr[name] = interpolateFn(scope);
8804
8805                         ($$observers[name] || ($$observers[name] = [])).$$inter = true;
8806                         (attr.$$observers && attr.$$observers[name].$$scope || scope).
8807                           $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
8808                             //special case for class attribute addition + removal
8809                             //so that class changes can tap into the animation
8810                             //hooks provided by the $animate service. Be sure to
8811                             //skip animations when the first digest occurs (when
8812                             //both the new and the old values are the same) since
8813                             //the CSS classes are the non-interpolated values
8814                             if (name === 'class' && newValue != oldValue) {
8815                               attr.$updateClass(newValue, oldValue);
8816                             } else {
8817                               attr.$set(name, newValue);
8818                             }
8819                           });
8820                       }
8821                     };
8822                   }
8823               });
8824             }
8825
8826
8827             /**
8828              * This is a special jqLite.replaceWith, which can replace items which
8829              * have no parents, provided that the containing jqLite collection is provided.
8830              *
8831              * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
8832              *                               in the root of the tree.
8833              * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
8834              *                                  the shell, but replace its DOM node reference.
8835              * @param {Node} newNode The new DOM node.
8836              */
8837             function replaceWith($rootElement, elementsToRemove, newNode) {
8838               var firstElementToRemove = elementsToRemove[0],
8839                   removeCount = elementsToRemove.length,
8840                   parent = firstElementToRemove.parentNode,
8841                   i, ii;
8842
8843               if ($rootElement) {
8844                 for (i = 0, ii = $rootElement.length; i < ii; i++) {
8845                   if ($rootElement[i] == firstElementToRemove) {
8846                     $rootElement[i++] = newNode;
8847                     for (var j = i, j2 = j + removeCount - 1,
8848                              jj = $rootElement.length;
8849                          j < jj; j++, j2++) {
8850                       if (j2 < jj) {
8851                         $rootElement[j] = $rootElement[j2];
8852                       } else {
8853                         delete $rootElement[j];
8854                       }
8855                     }
8856                     $rootElement.length -= removeCount - 1;
8857
8858                     // If the replaced element is also the jQuery .context then replace it
8859                     // .context is a deprecated jQuery api, so we should set it only when jQuery set it
8860                     // http://api.jquery.com/context/
8861                     if ($rootElement.context === firstElementToRemove) {
8862                       $rootElement.context = newNode;
8863                     }
8864                     break;
8865                   }
8866                 }
8867               }
8868
8869               if (parent) {
8870                 parent.replaceChild(newNode, firstElementToRemove);
8871               }
8872
8873               // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
8874               var fragment = document.createDocumentFragment();
8875               fragment.appendChild(firstElementToRemove);
8876
8877               if (jqLite.hasData(firstElementToRemove)) {
8878                 // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8879                 // data here because there's no public interface in jQuery to do that and copying over
8880                 // event listeners (which is the main use of private data) wouldn't work anyway.
8881                 jqLite.data(newNode, jqLite.data(firstElementToRemove));
8882
8883                 // Remove data of the replaced element. We cannot just call .remove()
8884                 // on the element it since that would deallocate scope that is needed
8885                 // for the new node. Instead, remove the data "manually".
8886                 if (!jQuery) {
8887                   delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8888                 } else {
8889                   // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8890                   // the replaced element. The cleanData version monkey-patched by Angular would cause
8891                   // the scope to be trashed and we do need the very same scope to work with the new
8892                   // element. However, we cannot just cache the non-patched version and use it here as
8893                   // that would break if another library patches the method after Angular does (one
8894                   // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8895                   // skipped this one time.
8896                   skipDestroyOnNextJQueryCleanData = true;
8897                   jQuery.cleanData([firstElementToRemove]);
8898                 }
8899               }
8900
8901               for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8902                 var element = elementsToRemove[k];
8903                 jqLite(element).remove(); // must do this way to clean up expando
8904                 fragment.appendChild(element);
8905                 delete elementsToRemove[k];
8906               }
8907
8908               elementsToRemove[0] = newNode;
8909               elementsToRemove.length = 1;
8910             }
8911
8912
8913             function cloneAndAnnotateFn(fn, annotation) {
8914               return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
8915             }
8916
8917
8918             function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
8919               try {
8920                 linkFn(scope, $element, attrs, controllers, transcludeFn);
8921               } catch (e) {
8922                 $exceptionHandler(e, startingTag($element));
8923               }
8924             }
8925
8926
8927             // Set up $watches for isolate scope and controller bindings. This process
8928             // only occurs for isolate scopes and new scopes with controllerAs.
8929             function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
8930               var removeWatchCollection = [];
8931               forEach(bindings, function(definition, scopeName) {
8932                 var attrName = definition.attrName,
8933                 optional = definition.optional,
8934                 mode = definition.mode, // @, =, or &
8935                 lastValue,
8936                 parentGet, parentSet, compare;
8937
8938                 switch (mode) {
8939
8940                   case '@':
8941                     if (!optional && !hasOwnProperty.call(attrs, attrName)) {
8942                       destination[scopeName] = attrs[attrName] = void 0;
8943                     }
8944                     attrs.$observe(attrName, function(value) {
8945                       if (isString(value)) {
8946                         destination[scopeName] = value;
8947                       }
8948                     });
8949                     attrs.$$observers[attrName].$$scope = scope;
8950                     if (isString(attrs[attrName])) {
8951                       // If the attribute has been provided then we trigger an interpolation to ensure
8952                       // the value is there for use in the link fn
8953                       destination[scopeName] = $interpolate(attrs[attrName])(scope);
8954                     }
8955                     break;
8956
8957                   case '=':
8958                     if (!hasOwnProperty.call(attrs, attrName)) {
8959                       if (optional) break;
8960                       attrs[attrName] = void 0;
8961                     }
8962                     if (optional && !attrs[attrName]) break;
8963
8964                     parentGet = $parse(attrs[attrName]);
8965                     if (parentGet.literal) {
8966                       compare = equals;
8967                     } else {
8968                       compare = function(a, b) { return a === b || (a !== a && b !== b); };
8969                     }
8970                     parentSet = parentGet.assign || function() {
8971                       // reset the change, or we will throw this exception on every $digest
8972                       lastValue = destination[scopeName] = parentGet(scope);
8973                       throw $compileMinErr('nonassign',
8974                           "Expression '{0}' used with directive '{1}' is non-assignable!",
8975                           attrs[attrName], directive.name);
8976                     };
8977                     lastValue = destination[scopeName] = parentGet(scope);
8978                     var parentValueWatch = function parentValueWatch(parentValue) {
8979                       if (!compare(parentValue, destination[scopeName])) {
8980                         // we are out of sync and need to copy
8981                         if (!compare(parentValue, lastValue)) {
8982                           // parent changed and it has precedence
8983                           destination[scopeName] = parentValue;
8984                         } else {
8985                           // if the parent can be assigned then do so
8986                           parentSet(scope, parentValue = destination[scopeName]);
8987                         }
8988                       }
8989                       return lastValue = parentValue;
8990                     };
8991                     parentValueWatch.$stateful = true;
8992                     var removeWatch;
8993                     if (definition.collection) {
8994                       removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
8995                     } else {
8996                       removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
8997                     }
8998                     removeWatchCollection.push(removeWatch);
8999                     break;
9000
9001                   case '&':
9002                     // Don't assign Object.prototype method to scope
9003                     parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
9004
9005                     // Don't assign noop to destination if expression is not valid
9006                     if (parentGet === noop && optional) break;
9007
9008                     destination[scopeName] = function(locals) {
9009                       return parentGet(scope, locals);
9010                     };
9011                     break;
9012                 }
9013               });
9014
9015               return removeWatchCollection.length && function removeWatches() {
9016                 for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
9017                   removeWatchCollection[i]();
9018                 }
9019               };
9020             }
9021           }];
9022         }
9023
9024         var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
9025         /**
9026          * Converts all accepted directives format into proper directive name.
9027          * @param name Name to normalize
9028          */
9029         function directiveNormalize(name) {
9030           return camelCase(name.replace(PREFIX_REGEXP, ''));
9031         }
9032
9033         /**
9034          * @ngdoc type
9035          * @name $compile.directive.Attributes
9036          *
9037          * @description
9038          * A shared object between directive compile / linking functions which contains normalized DOM
9039          * element attributes. The values reflect current binding state `{{ }}`. The normalization is
9040          * needed since all of these are treated as equivalent in Angular:
9041          *
9042          * ```
9043          *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
9044          * ```
9045          */
9046
9047         /**
9048          * @ngdoc property
9049          * @name $compile.directive.Attributes#$attr
9050          *
9051          * @description
9052          * A map of DOM element attribute names to the normalized name. This is
9053          * needed to do reverse lookup from normalized name back to actual name.
9054          */
9055
9056
9057         /**
9058          * @ngdoc method
9059          * @name $compile.directive.Attributes#$set
9060          * @kind function
9061          *
9062          * @description
9063          * Set DOM element attribute value.
9064          *
9065          *
9066          * @param {string} name Normalized element attribute name of the property to modify. The name is
9067          *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
9068          *          property to the original name.
9069          * @param {string} value Value to set the attribute to. The value can be an interpolated string.
9070          */
9071
9072
9073
9074         /**
9075          * Closure compiler type information
9076          */
9077
9078         function nodesetLinkingFn(
9079           /* angular.Scope */ scope,
9080           /* NodeList */ nodeList,
9081           /* Element */ rootElement,
9082           /* function(Function) */ boundTranscludeFn
9083         ) {}
9084
9085         function directiveLinkingFn(
9086           /* nodesetLinkingFn */ nodesetLinkingFn,
9087           /* angular.Scope */ scope,
9088           /* Node */ node,
9089           /* Element */ rootElement,
9090           /* function(Function) */ boundTranscludeFn
9091         ) {}
9092
9093         function tokenDifference(str1, str2) {
9094           var values = '',
9095               tokens1 = str1.split(/\s+/),
9096               tokens2 = str2.split(/\s+/);
9097
9098           outer:
9099           for (var i = 0; i < tokens1.length; i++) {
9100             var token = tokens1[i];
9101             for (var j = 0; j < tokens2.length; j++) {
9102               if (token == tokens2[j]) continue outer;
9103             }
9104             values += (values.length > 0 ? ' ' : '') + token;
9105           }
9106           return values;
9107         }
9108
9109         function removeComments(jqNodes) {
9110           jqNodes = jqLite(jqNodes);
9111           var i = jqNodes.length;
9112
9113           if (i <= 1) {
9114             return jqNodes;
9115           }
9116
9117           while (i--) {
9118             var node = jqNodes[i];
9119             if (node.nodeType === NODE_TYPE_COMMENT) {
9120               splice.call(jqNodes, i, 1);
9121             }
9122           }
9123           return jqNodes;
9124         }
9125
9126         var $controllerMinErr = minErr('$controller');
9127
9128
9129         var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
9130         function identifierForController(controller, ident) {
9131           if (ident && isString(ident)) return ident;
9132           if (isString(controller)) {
9133             var match = CNTRL_REG.exec(controller);
9134             if (match) return match[3];
9135           }
9136         }
9137
9138
9139         /**
9140          * @ngdoc provider
9141          * @name $controllerProvider
9142          * @description
9143          * The {@link ng.$controller $controller service} is used by Angular to create new
9144          * controllers.
9145          *
9146          * This provider allows controller registration via the
9147          * {@link ng.$controllerProvider#register register} method.
9148          */
9149         function $ControllerProvider() {
9150           var controllers = {},
9151               globals = false;
9152
9153           /**
9154            * @ngdoc method
9155            * @name $controllerProvider#register
9156            * @param {string|Object} name Controller name, or an object map of controllers where the keys are
9157            *    the names and the values are the constructors.
9158            * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
9159            *    annotations in the array notation).
9160            */
9161           this.register = function(name, constructor) {
9162             assertNotHasOwnProperty(name, 'controller');
9163             if (isObject(name)) {
9164               extend(controllers, name);
9165             } else {
9166               controllers[name] = constructor;
9167             }
9168           };
9169
9170           /**
9171            * @ngdoc method
9172            * @name $controllerProvider#allowGlobals
9173            * @description If called, allows `$controller` to find controller constructors on `window`
9174            */
9175           this.allowGlobals = function() {
9176             globals = true;
9177           };
9178
9179
9180           this.$get = ['$injector', '$window', function($injector, $window) {
9181
9182             /**
9183              * @ngdoc service
9184              * @name $controller
9185              * @requires $injector
9186              *
9187              * @param {Function|string} constructor If called with a function then it's considered to be the
9188              *    controller constructor function. Otherwise it's considered to be a string which is used
9189              *    to retrieve the controller constructor using the following steps:
9190              *
9191              *    * check if a controller with given name is registered via `$controllerProvider`
9192              *    * check if evaluating the string on the current scope returns a constructor
9193              *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
9194              *      `window` object (not recommended)
9195              *
9196              *    The string can use the `controller as property` syntax, where the controller instance is published
9197              *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
9198              *    to work correctly.
9199              *
9200              * @param {Object} locals Injection locals for Controller.
9201              * @return {Object} Instance of given controller.
9202              *
9203              * @description
9204              * `$controller` service is responsible for instantiating controllers.
9205              *
9206              * It's just a simple call to {@link auto.$injector $injector}, but extracted into
9207              * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
9208              */
9209             return function(expression, locals, later, ident) {
9210               // PRIVATE API:
9211               //   param `later` --- indicates that the controller's constructor is invoked at a later time.
9212               //                     If true, $controller will allocate the object with the correct
9213               //                     prototype chain, but will not invoke the controller until a returned
9214               //                     callback is invoked.
9215               //   param `ident` --- An optional label which overrides the label parsed from the controller
9216               //                     expression, if any.
9217               var instance, match, constructor, identifier;
9218               later = later === true;
9219               if (ident && isString(ident)) {
9220                 identifier = ident;
9221               }
9222
9223               if (isString(expression)) {
9224                 match = expression.match(CNTRL_REG);
9225                 if (!match) {
9226                   throw $controllerMinErr('ctrlfmt',
9227                     "Badly formed controller string '{0}'. " +
9228                     "Must match `__name__ as __id__` or `__name__`.", expression);
9229                 }
9230                 constructor = match[1],
9231                 identifier = identifier || match[3];
9232                 expression = controllers.hasOwnProperty(constructor)
9233                     ? controllers[constructor]
9234                     : getter(locals.$scope, constructor, true) ||
9235                         (globals ? getter($window, constructor, true) : undefined);
9236
9237                 assertArgFn(expression, constructor, true);
9238               }
9239
9240               if (later) {
9241                 // Instantiate controller later:
9242                 // This machinery is used to create an instance of the object before calling the
9243                 // controller's constructor itself.
9244                 //
9245                 // This allows properties to be added to the controller before the constructor is
9246                 // invoked. Primarily, this is used for isolate scope bindings in $compile.
9247                 //
9248                 // This feature is not intended for use by applications, and is thus not documented
9249                 // publicly.
9250                 // Object creation: http://jsperf.com/create-constructor/2
9251                 var controllerPrototype = (isArray(expression) ?
9252                   expression[expression.length - 1] : expression).prototype;
9253                 instance = Object.create(controllerPrototype || null);
9254
9255                 if (identifier) {
9256                   addIdentifier(locals, identifier, instance, constructor || expression.name);
9257                 }
9258
9259                 var instantiate;
9260                 return instantiate = extend(function() {
9261                   var result = $injector.invoke(expression, instance, locals, constructor);
9262                   if (result !== instance && (isObject(result) || isFunction(result))) {
9263                     instance = result;
9264                     if (identifier) {
9265                       // If result changed, re-assign controllerAs value to scope.
9266                       addIdentifier(locals, identifier, instance, constructor || expression.name);
9267                     }
9268                   }
9269                   return instance;
9270                 }, {
9271                   instance: instance,
9272                   identifier: identifier
9273                 });
9274               }
9275
9276               instance = $injector.instantiate(expression, locals, constructor);
9277
9278               if (identifier) {
9279                 addIdentifier(locals, identifier, instance, constructor || expression.name);
9280               }
9281
9282               return instance;
9283             };
9284
9285             function addIdentifier(locals, identifier, instance, name) {
9286               if (!(locals && isObject(locals.$scope))) {
9287                 throw minErr('$controller')('noscp',
9288                   "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
9289                   name, identifier);
9290               }
9291
9292               locals.$scope[identifier] = instance;
9293             }
9294           }];
9295         }
9296
9297         /**
9298          * @ngdoc service
9299          * @name $document
9300          * @requires $window
9301          *
9302          * @description
9303          * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
9304          *
9305          * @example
9306            <example module="documentExample">
9307              <file name="index.html">
9308                <div ng-controller="ExampleController">
9309                  <p>$document title: <b ng-bind="title"></b></p>
9310                  <p>window.document title: <b ng-bind="windowTitle"></b></p>
9311                </div>
9312              </file>
9313              <file name="script.js">
9314                angular.module('documentExample', [])
9315                  .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
9316                    $scope.title = $document[0].title;
9317                    $scope.windowTitle = angular.element(window.document)[0].title;
9318                  }]);
9319              </file>
9320            </example>
9321          */
9322         function $DocumentProvider() {
9323           this.$get = ['$window', function(window) {
9324             return jqLite(window.document);
9325           }];
9326         }
9327
9328         /**
9329          * @ngdoc service
9330          * @name $exceptionHandler
9331          * @requires ng.$log
9332          *
9333          * @description
9334          * Any uncaught exception in angular expressions is delegated to this service.
9335          * The default implementation simply delegates to `$log.error` which logs it into
9336          * the browser console.
9337          *
9338          * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
9339          * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
9340          *
9341          * ## Example:
9342          *
9343          * ```js
9344          *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
9345          *     return function(exception, cause) {
9346          *       exception.message += ' (caused by "' + cause + '")';
9347          *       throw exception;
9348          *     };
9349          *   });
9350          * ```
9351          *
9352          * This example will override the normal action of `$exceptionHandler`, to make angular
9353          * exceptions fail hard when they happen, instead of just logging to the console.
9354          *
9355          * <hr />
9356          * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
9357          * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
9358          * (unless executed during a digest).
9359          *
9360          * If you wish, you can manually delegate exceptions, e.g.
9361          * `try { ... } catch(e) { $exceptionHandler(e); }`
9362          *
9363          * @param {Error} exception Exception associated with the error.
9364          * @param {string=} cause optional information about the context in which
9365          *       the error was thrown.
9366          *
9367          */
9368         function $ExceptionHandlerProvider() {
9369           this.$get = ['$log', function($log) {
9370             return function(exception, cause) {
9371               $log.error.apply($log, arguments);
9372             };
9373           }];
9374         }
9375
9376         var $$ForceReflowProvider = function() {
9377           this.$get = ['$document', function($document) {
9378             return function(domNode) {
9379               //the line below will force the browser to perform a repaint so
9380               //that all the animated elements within the animation frame will
9381               //be properly updated and drawn on screen. This is required to
9382               //ensure that the preparation animation is properly flushed so that
9383               //the active state picks up from there. DO NOT REMOVE THIS LINE.
9384               //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
9385               //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
9386               //WILL TAKE YEARS AWAY FROM YOUR LIFE.
9387               if (domNode) {
9388                 if (!domNode.nodeType && domNode instanceof jqLite) {
9389                   domNode = domNode[0];
9390                 }
9391               } else {
9392                 domNode = $document[0].body;
9393               }
9394               return domNode.offsetWidth + 1;
9395             };
9396           }];
9397         };
9398
9399         var APPLICATION_JSON = 'application/json';
9400         var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
9401         var JSON_START = /^\[|^\{(?!\{)/;
9402         var JSON_ENDS = {
9403           '[': /]$/,
9404           '{': /}$/
9405         };
9406         var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
9407         var $httpMinErr = minErr('$http');
9408         var $httpMinErrLegacyFn = function(method) {
9409           return function() {
9410             throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
9411           };
9412         };
9413
9414         function serializeValue(v) {
9415           if (isObject(v)) {
9416             return isDate(v) ? v.toISOString() : toJson(v);
9417           }
9418           return v;
9419         }
9420
9421
9422         function $HttpParamSerializerProvider() {
9423           /**
9424            * @ngdoc service
9425            * @name $httpParamSerializer
9426            * @description
9427            *
9428            * Default {@link $http `$http`} params serializer that converts objects to strings
9429            * according to the following rules:
9430            *
9431            * * `{'foo': 'bar'}` results in `foo=bar`
9432            * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
9433            * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
9434            * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
9435            *
9436            * Note that serializer will sort the request parameters alphabetically.
9437            * */
9438
9439           this.$get = function() {
9440             return function ngParamSerializer(params) {
9441               if (!params) return '';
9442               var parts = [];
9443               forEachSorted(params, function(value, key) {
9444                 if (value === null || isUndefined(value)) return;
9445                 if (isArray(value)) {
9446                   forEach(value, function(v, k) {
9447                     parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
9448                   });
9449                 } else {
9450                   parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
9451                 }
9452               });
9453
9454               return parts.join('&');
9455             };
9456           };
9457         }
9458
9459         function $HttpParamSerializerJQLikeProvider() {
9460           /**
9461            * @ngdoc service
9462            * @name $httpParamSerializerJQLike
9463            * @description
9464            *
9465            * Alternative {@link $http `$http`} params serializer that follows
9466            * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
9467            * The serializer will also sort the params alphabetically.
9468            *
9469            * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
9470            *
9471            * ```js
9472            * $http({
9473            *   url: myUrl,
9474            *   method: 'GET',
9475            *   params: myParams,
9476            *   paramSerializer: '$httpParamSerializerJQLike'
9477            * });
9478            * ```
9479            *
9480            * It is also possible to set it as the default `paramSerializer` in the
9481            * {@link $httpProvider#defaults `$httpProvider`}.
9482            *
9483            * Additionally, you can inject the serializer and use it explicitly, for example to serialize
9484            * form data for submission:
9485            *
9486            * ```js
9487            * .controller(function($http, $httpParamSerializerJQLike) {
9488            *   //...
9489            *
9490            *   $http({
9491            *     url: myUrl,
9492            *     method: 'POST',
9493            *     data: $httpParamSerializerJQLike(myData),
9494            *     headers: {
9495            *       'Content-Type': 'application/x-www-form-urlencoded'
9496            *     }
9497            *   });
9498            *
9499            * });
9500            * ```
9501            *
9502            * */
9503           this.$get = function() {
9504             return function jQueryLikeParamSerializer(params) {
9505               if (!params) return '';
9506               var parts = [];
9507               serialize(params, '', true);
9508               return parts.join('&');
9509
9510               function serialize(toSerialize, prefix, topLevel) {
9511                 if (toSerialize === null || isUndefined(toSerialize)) return;
9512                 if (isArray(toSerialize)) {
9513                   forEach(toSerialize, function(value, index) {
9514                     serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
9515                   });
9516                 } else if (isObject(toSerialize) && !isDate(toSerialize)) {
9517                   forEachSorted(toSerialize, function(value, key) {
9518                     serialize(value, prefix +
9519                         (topLevel ? '' : '[') +
9520                         key +
9521                         (topLevel ? '' : ']'));
9522                   });
9523                 } else {
9524                   parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
9525                 }
9526               }
9527             };
9528           };
9529         }
9530
9531         function defaultHttpResponseTransform(data, headers) {
9532           if (isString(data)) {
9533             // Strip json vulnerability protection prefix and trim whitespace
9534             var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
9535
9536             if (tempData) {
9537               var contentType = headers('Content-Type');
9538               if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
9539                 data = fromJson(tempData);
9540               }
9541             }
9542           }
9543
9544           return data;
9545         }
9546
9547         function isJsonLike(str) {
9548             var jsonStart = str.match(JSON_START);
9549             return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
9550         }
9551
9552         /**
9553          * Parse headers into key value object
9554          *
9555          * @param {string} headers Raw headers as a string
9556          * @returns {Object} Parsed headers as key value object
9557          */
9558         function parseHeaders(headers) {
9559           var parsed = createMap(), i;
9560
9561           function fillInParsed(key, val) {
9562             if (key) {
9563               parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
9564             }
9565           }
9566
9567           if (isString(headers)) {
9568             forEach(headers.split('\n'), function(line) {
9569               i = line.indexOf(':');
9570               fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
9571             });
9572           } else if (isObject(headers)) {
9573             forEach(headers, function(headerVal, headerKey) {
9574               fillInParsed(lowercase(headerKey), trim(headerVal));
9575             });
9576           }
9577
9578           return parsed;
9579         }
9580
9581
9582         /**
9583          * Returns a function that provides access to parsed headers.
9584          *
9585          * Headers are lazy parsed when first requested.
9586          * @see parseHeaders
9587          *
9588          * @param {(string|Object)} headers Headers to provide access to.
9589          * @returns {function(string=)} Returns a getter function which if called with:
9590          *
9591          *   - if called with single an argument returns a single header value or null
9592          *   - if called with no arguments returns an object containing all headers.
9593          */
9594         function headersGetter(headers) {
9595           var headersObj;
9596
9597           return function(name) {
9598             if (!headersObj) headersObj =  parseHeaders(headers);
9599
9600             if (name) {
9601               var value = headersObj[lowercase(name)];
9602               if (value === void 0) {
9603                 value = null;
9604               }
9605               return value;
9606             }
9607
9608             return headersObj;
9609           };
9610         }
9611
9612
9613         /**
9614          * Chain all given functions
9615          *
9616          * This function is used for both request and response transforming
9617          *
9618          * @param {*} data Data to transform.
9619          * @param {function(string=)} headers HTTP headers getter fn.
9620          * @param {number} status HTTP status code of the response.
9621          * @param {(Function|Array.<Function>)} fns Function or an array of functions.
9622          * @returns {*} Transformed data.
9623          */
9624         function transformData(data, headers, status, fns) {
9625           if (isFunction(fns)) {
9626             return fns(data, headers, status);
9627           }
9628
9629           forEach(fns, function(fn) {
9630             data = fn(data, headers, status);
9631           });
9632
9633           return data;
9634         }
9635
9636
9637         function isSuccess(status) {
9638           return 200 <= status && status < 300;
9639         }
9640
9641
9642         /**
9643          * @ngdoc provider
9644          * @name $httpProvider
9645          * @description
9646          * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
9647          * */
9648         function $HttpProvider() {
9649           /**
9650            * @ngdoc property
9651            * @name $httpProvider#defaults
9652            * @description
9653            *
9654            * Object containing default values for all {@link ng.$http $http} requests.
9655            *
9656            * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
9657            * that will provide the cache for all requests who set their `cache` property to `true`.
9658            * If you set the `defaults.cache = false` then only requests that specify their own custom
9659            * cache object will be cached. See {@link $http#caching $http Caching} for more information.
9660            *
9661            * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
9662            * Defaults value is `'XSRF-TOKEN'`.
9663            *
9664            * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
9665            * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
9666            *
9667            * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
9668            * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
9669            * setting default headers.
9670            *     - **`defaults.headers.common`**
9671            *     - **`defaults.headers.post`**
9672            *     - **`defaults.headers.put`**
9673            *     - **`defaults.headers.patch`**
9674            *
9675            *
9676            * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
9677            *  used to the prepare string representation of request parameters (specified as an object).
9678            *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
9679            *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
9680            *
9681            **/
9682           var defaults = this.defaults = {
9683             // transform incoming response data
9684             transformResponse: [defaultHttpResponseTransform],
9685
9686             // transform outgoing request data
9687             transformRequest: [function(d) {
9688               return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
9689             }],
9690
9691             // default headers
9692             headers: {
9693               common: {
9694                 'Accept': 'application/json, text/plain, */*'
9695               },
9696               post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9697               put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9698               patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
9699             },
9700
9701             xsrfCookieName: 'XSRF-TOKEN',
9702             xsrfHeaderName: 'X-XSRF-TOKEN',
9703
9704             paramSerializer: '$httpParamSerializer'
9705           };
9706
9707           var useApplyAsync = false;
9708           /**
9709            * @ngdoc method
9710            * @name $httpProvider#useApplyAsync
9711            * @description
9712            *
9713            * Configure $http service to combine processing of multiple http responses received at around
9714            * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
9715            * significant performance improvement for bigger applications that make many HTTP requests
9716            * concurrently (common during application bootstrap).
9717            *
9718            * Defaults to false. If no value is specified, returns the current configured value.
9719            *
9720            * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
9721            *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
9722            *    to load and share the same digest cycle.
9723            *
9724            * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9725            *    otherwise, returns the current configured value.
9726            **/
9727           this.useApplyAsync = function(value) {
9728             if (isDefined(value)) {
9729               useApplyAsync = !!value;
9730               return this;
9731             }
9732             return useApplyAsync;
9733           };
9734
9735           var useLegacyPromise = true;
9736           /**
9737            * @ngdoc method
9738            * @name $httpProvider#useLegacyPromiseExtensions
9739            * @description
9740            *
9741            * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
9742            * This should be used to make sure that applications work without these methods.
9743            *
9744            * Defaults to true. If no value is specified, returns the current configured value.
9745            *
9746            * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
9747            *
9748            * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9749            *    otherwise, returns the current configured value.
9750            **/
9751           this.useLegacyPromiseExtensions = function(value) {
9752             if (isDefined(value)) {
9753               useLegacyPromise = !!value;
9754               return this;
9755             }
9756             return useLegacyPromise;
9757           };
9758
9759           /**
9760            * @ngdoc property
9761            * @name $httpProvider#interceptors
9762            * @description
9763            *
9764            * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
9765            * pre-processing of request or postprocessing of responses.
9766            *
9767            * These service factories are ordered by request, i.e. they are applied in the same order as the
9768            * array, on request, but reverse order, on response.
9769            *
9770            * {@link ng.$http#interceptors Interceptors detailed info}
9771            **/
9772           var interceptorFactories = this.interceptors = [];
9773
9774           this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
9775               function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
9776
9777             var defaultCache = $cacheFactory('$http');
9778
9779             /**
9780              * Make sure that default param serializer is exposed as a function
9781              */
9782             defaults.paramSerializer = isString(defaults.paramSerializer) ?
9783               $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
9784
9785             /**
9786              * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
9787              * The reversal is needed so that we can build up the interception chain around the
9788              * server request.
9789              */
9790             var reversedInterceptors = [];
9791
9792             forEach(interceptorFactories, function(interceptorFactory) {
9793               reversedInterceptors.unshift(isString(interceptorFactory)
9794                   ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
9795             });
9796
9797             /**
9798              * @ngdoc service
9799              * @kind function
9800              * @name $http
9801              * @requires ng.$httpBackend
9802              * @requires $cacheFactory
9803              * @requires $rootScope
9804              * @requires $q
9805              * @requires $injector
9806              *
9807              * @description
9808              * The `$http` service is a core Angular service that facilitates communication with the remote
9809              * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
9810              * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
9811              *
9812              * For unit testing applications that use `$http` service, see
9813              * {@link ngMock.$httpBackend $httpBackend mock}.
9814              *
9815              * For a higher level of abstraction, please check out the {@link ngResource.$resource
9816              * $resource} service.
9817              *
9818              * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
9819              * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
9820              * it is important to familiarize yourself with these APIs and the guarantees they provide.
9821              *
9822              *
9823              * ## General usage
9824              * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
9825              * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
9826              *
9827              * ```js
9828              *   // Simple GET request example:
9829              *   $http({
9830              *     method: 'GET',
9831              *     url: '/someUrl'
9832              *   }).then(function successCallback(response) {
9833              *       // this callback will be called asynchronously
9834              *       // when the response is available
9835              *     }, function errorCallback(response) {
9836              *       // called asynchronously if an error occurs
9837              *       // or server returns response with an error status.
9838              *     });
9839              * ```
9840              *
9841              * The response object has these properties:
9842              *
9843              *   - **data** – `{string|Object}` – The response body transformed with the transform
9844              *     functions.
9845              *   - **status** – `{number}` – HTTP status code of the response.
9846              *   - **headers** – `{function([headerName])}` – Header getter function.
9847              *   - **config** – `{Object}` – The configuration object that was used to generate the request.
9848              *   - **statusText** – `{string}` – HTTP status text of the response.
9849              *
9850              * A response status code between 200 and 299 is considered a success status and
9851              * will result in the success callback being called. Note that if the response is a redirect,
9852              * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
9853              * called for such responses.
9854              *
9855              *
9856              * ## Shortcut methods
9857              *
9858              * Shortcut methods are also available. All shortcut methods require passing in the URL, and
9859              * request data must be passed in for POST/PUT requests. An optional config can be passed as the
9860              * last argument.
9861              *
9862              * ```js
9863              *   $http.get('/someUrl', config).then(successCallback, errorCallback);
9864              *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
9865              * ```
9866              *
9867              * Complete list of shortcut methods:
9868              *
9869              * - {@link ng.$http#get $http.get}
9870              * - {@link ng.$http#head $http.head}
9871              * - {@link ng.$http#post $http.post}
9872              * - {@link ng.$http#put $http.put}
9873              * - {@link ng.$http#delete $http.delete}
9874              * - {@link ng.$http#jsonp $http.jsonp}
9875              * - {@link ng.$http#patch $http.patch}
9876              *
9877              *
9878              * ## Writing Unit Tests that use $http
9879              * When unit testing (using {@link ngMock ngMock}), it is necessary to call
9880              * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
9881              * request using trained responses.
9882              *
9883              * ```
9884              * $httpBackend.expectGET(...);
9885              * $http.get(...);
9886              * $httpBackend.flush();
9887              * ```
9888              *
9889              * ## Deprecation Notice
9890              * <div class="alert alert-danger">
9891              *   The `$http` legacy promise methods `success` and `error` have been deprecated.
9892              *   Use the standard `then` method instead.
9893              *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
9894              *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
9895              * </div>
9896              *
9897              * ## Setting HTTP Headers
9898              *
9899              * The $http service will automatically add certain HTTP headers to all requests. These defaults
9900              * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
9901              * object, which currently contains this default configuration:
9902              *
9903              * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
9904              *   - `Accept: application/json, text/plain, * / *`
9905              * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
9906              *   - `Content-Type: application/json`
9907              * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
9908              *   - `Content-Type: application/json`
9909              *
9910              * To add or overwrite these defaults, simply add or remove a property from these configuration
9911              * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
9912              * with the lowercased HTTP method name as the key, e.g.
9913              * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
9914              *
9915              * The defaults can also be set at runtime via the `$http.defaults` object in the same
9916              * fashion. For example:
9917              *
9918              * ```
9919              * module.run(function($http) {
9920              *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
9921              * });
9922              * ```
9923              *
9924              * In addition, you can supply a `headers` property in the config object passed when
9925              * calling `$http(config)`, which overrides the defaults without changing them globally.
9926              *
9927              * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
9928              * Use the `headers` property, setting the desired header to `undefined`. For example:
9929              *
9930              * ```js
9931              * var req = {
9932              *  method: 'POST',
9933              *  url: 'http://example.com',
9934              *  headers: {
9935              *    'Content-Type': undefined
9936              *  },
9937              *  data: { test: 'test' }
9938              * }
9939              *
9940              * $http(req).then(function(){...}, function(){...});
9941              * ```
9942              *
9943              * ## Transforming Requests and Responses
9944              *
9945              * Both requests and responses can be transformed using transformation functions: `transformRequest`
9946              * and `transformResponse`. These properties can be a single function that returns
9947              * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
9948              * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
9949              *
9950              * ### Default Transformations
9951              *
9952              * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
9953              * `defaults.transformResponse` properties. If a request does not provide its own transformations
9954              * then these will be applied.
9955              *
9956              * You can augment or replace the default transformations by modifying these properties by adding to or
9957              * replacing the array.
9958              *
9959              * Angular provides the following default transformations:
9960              *
9961              * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
9962              *
9963              * - If the `data` property of the request configuration object contains an object, serialize it
9964              *   into JSON format.
9965              *
9966              * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
9967              *
9968              *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
9969              *  - If JSON response is detected, deserialize it using a JSON parser.
9970              *
9971              *
9972              * ### Overriding the Default Transformations Per Request
9973              *
9974              * If you wish override the request/response transformations only for a single request then provide
9975              * `transformRequest` and/or `transformResponse` properties on the configuration object passed
9976              * into `$http`.
9977              *
9978              * Note that if you provide these properties on the config object the default transformations will be
9979              * overwritten. If you wish to augment the default transformations then you must include them in your
9980              * local transformation array.
9981              *
9982              * The following code demonstrates adding a new response transformation to be run after the default response
9983              * transformations have been run.
9984              *
9985              * ```js
9986              * function appendTransform(defaults, transform) {
9987              *
9988              *   // We can't guarantee that the default transformation is an array
9989              *   defaults = angular.isArray(defaults) ? defaults : [defaults];
9990              *
9991              *   // Append the new transformation to the defaults
9992              *   return defaults.concat(transform);
9993              * }
9994              *
9995              * $http({
9996              *   url: '...',
9997              *   method: 'GET',
9998              *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
9999              *     return doTransform(value);
10000              *   })
10001              * });
10002              * ```
10003              *
10004              *
10005              * ## Caching
10006              *
10007              * To enable caching, set the request configuration `cache` property to `true` (to use default
10008              * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
10009              * When the cache is enabled, `$http` stores the response from the server in the specified
10010              * cache. The next time the same request is made, the response is served from the cache without
10011              * sending a request to the server.
10012              *
10013              * Note that even if the response is served from cache, delivery of the data is asynchronous in
10014              * the same way that real requests are.
10015              *
10016              * If there are multiple GET requests for the same URL that should be cached using the same
10017              * cache, but the cache is not populated yet, only one request to the server will be made and
10018              * the remaining requests will be fulfilled using the response from the first request.
10019              *
10020              * You can change the default cache to a new object (built with
10021              * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
10022              * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
10023              * their `cache` property to `true` will now use this cache object.
10024              *
10025              * If you set the default cache to `false` then only requests that specify their own custom
10026              * cache object will be cached.
10027              *
10028              * ## Interceptors
10029              *
10030              * Before you start creating interceptors, be sure to understand the
10031              * {@link ng.$q $q and deferred/promise APIs}.
10032              *
10033              * For purposes of global error handling, authentication, or any kind of synchronous or
10034              * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
10035              * able to intercept requests before they are handed to the server and
10036              * responses before they are handed over to the application code that
10037              * initiated these requests. The interceptors leverage the {@link ng.$q
10038              * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
10039              *
10040              * The interceptors are service factories that are registered with the `$httpProvider` by
10041              * adding them to the `$httpProvider.interceptors` array. The factory is called and
10042              * injected with dependencies (if specified) and returns the interceptor.
10043              *
10044              * There are two kinds of interceptors (and two kinds of rejection interceptors):
10045              *
10046              *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
10047              *     modify the `config` object or create a new one. The function needs to return the `config`
10048              *     object directly, or a promise containing the `config` or a new `config` object.
10049              *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
10050              *     resolved with a rejection.
10051              *   * `response`: interceptors get called with http `response` object. The function is free to
10052              *     modify the `response` object or create a new one. The function needs to return the `response`
10053              *     object directly, or as a promise containing the `response` or a new `response` object.
10054              *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
10055              *     resolved with a rejection.
10056              *
10057              *
10058              * ```js
10059              *   // register the interceptor as a service
10060              *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
10061              *     return {
10062              *       // optional method
10063              *       'request': function(config) {
10064              *         // do something on success
10065              *         return config;
10066              *       },
10067              *
10068              *       // optional method
10069              *      'requestError': function(rejection) {
10070              *         // do something on error
10071              *         if (canRecover(rejection)) {
10072              *           return responseOrNewPromise
10073              *         }
10074              *         return $q.reject(rejection);
10075              *       },
10076              *
10077              *
10078              *
10079              *       // optional method
10080              *       'response': function(response) {
10081              *         // do something on success
10082              *         return response;
10083              *       },
10084              *
10085              *       // optional method
10086              *      'responseError': function(rejection) {
10087              *         // do something on error
10088              *         if (canRecover(rejection)) {
10089              *           return responseOrNewPromise
10090              *         }
10091              *         return $q.reject(rejection);
10092              *       }
10093              *     };
10094              *   });
10095              *
10096              *   $httpProvider.interceptors.push('myHttpInterceptor');
10097              *
10098              *
10099              *   // alternatively, register the interceptor via an anonymous factory
10100              *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
10101              *     return {
10102              *      'request': function(config) {
10103              *          // same as above
10104              *       },
10105              *
10106              *       'response': function(response) {
10107              *          // same as above
10108              *       }
10109              *     };
10110              *   });
10111              * ```
10112              *
10113              * ## Security Considerations
10114              *
10115              * When designing web applications, consider security threats from:
10116              *
10117              * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
10118              * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
10119              *
10120              * Both server and the client must cooperate in order to eliminate these threats. Angular comes
10121              * pre-configured with strategies that address these issues, but for this to work backend server
10122              * cooperation is required.
10123              *
10124              * ### JSON Vulnerability Protection
10125              *
10126              * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
10127              * allows third party website to turn your JSON resource URL into
10128              * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
10129              * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
10130              * Angular will automatically strip the prefix before processing it as JSON.
10131              *
10132              * For example if your server needs to return:
10133              * ```js
10134              * ['one','two']
10135              * ```
10136              *
10137              * which is vulnerable to attack, your server can return:
10138              * ```js
10139              * )]}',
10140              * ['one','two']
10141              * ```
10142              *
10143              * Angular will strip the prefix, before processing the JSON.
10144              *
10145              *
10146              * ### Cross Site Request Forgery (XSRF) Protection
10147              *
10148              * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
10149              * an unauthorized site can gain your user's private data. Angular provides a mechanism
10150              * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
10151              * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
10152              * JavaScript that runs on your domain could read the cookie, your server can be assured that
10153              * the XHR came from JavaScript running on your domain. The header will not be set for
10154              * cross-domain requests.
10155              *
10156              * To take advantage of this, your server needs to set a token in a JavaScript readable session
10157              * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
10158              * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
10159              * that only JavaScript running on your domain could have sent the request. The token must be
10160              * unique for each user and must be verifiable by the server (to prevent the JavaScript from
10161              * making up its own tokens). We recommend that the token is a digest of your site's
10162              * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
10163              * for added security.
10164              *
10165              * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
10166              * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
10167              * or the per-request config object.
10168              *
10169              * In order to prevent collisions in environments where multiple Angular apps share the
10170              * same domain or subdomain, we recommend that each application uses unique cookie name.
10171              *
10172              * @param {object} config Object describing the request to be made and how it should be
10173              *    processed. The object has following properties:
10174              *
10175              *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
10176              *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
10177              *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
10178              *      with the `paramSerializer` and appended as GET parameters.
10179              *    - **data** – `{string|Object}` – Data to be sent as the request message data.
10180              *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
10181              *      HTTP headers to send to the server. If the return value of a function is null, the
10182              *      header will not be sent. Functions accept a config object as an argument.
10183              *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
10184              *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
10185              *    - **transformRequest** –
10186              *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
10187              *      transform function or an array of such functions. The transform function takes the http
10188              *      request body and headers and returns its transformed (typically serialized) version.
10189              *      See {@link ng.$http#overriding-the-default-transformations-per-request
10190              *      Overriding the Default Transformations}
10191              *    - **transformResponse** –
10192              *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
10193              *      transform function or an array of such functions. The transform function takes the http
10194              *      response body, headers and status and returns its transformed (typically deserialized) version.
10195              *      See {@link ng.$http#overriding-the-default-transformations-per-request
10196              *      Overriding the Default TransformationjqLiks}
10197              *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
10198              *      prepare the string representation of request parameters (specified as an object).
10199              *      If specified as string, it is interpreted as function registered with the
10200              *      {@link $injector $injector}, which means you can create your own serializer
10201              *      by registering it as a {@link auto.$provide#service service}.
10202              *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
10203              *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
10204              *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
10205              *      GET request, otherwise if a cache instance built with
10206              *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
10207              *      caching.
10208              *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
10209              *      that should abort the request when resolved.
10210              *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
10211              *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
10212              *      for more information.
10213              *    - **responseType** - `{string}` - see
10214              *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
10215              *
10216              * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
10217              *                        when the request succeeds or fails.
10218              *
10219              *
10220              * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
10221              *   requests. This is primarily meant to be used for debugging purposes.
10222              *
10223              *
10224              * @example
10225         <example module="httpExample">
10226         <file name="index.html">
10227           <div ng-controller="FetchController">
10228             <select ng-model="method" aria-label="Request method">
10229               <option>GET</option>
10230               <option>JSONP</option>
10231             </select>
10232             <input type="text" ng-model="url" size="80" aria-label="URL" />
10233             <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
10234             <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
10235             <button id="samplejsonpbtn"
10236               ng-click="updateModel('JSONP',
10237                             'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
10238               Sample JSONP
10239             </button>
10240             <button id="invalidjsonpbtn"
10241               ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
10242                 Invalid JSONP
10243               </button>
10244             <pre>http status code: {{status}}</pre>
10245             <pre>http response data: {{data}}</pre>
10246           </div>
10247         </file>
10248         <file name="script.js">
10249           angular.module('httpExample', [])
10250             .controller('FetchController', ['$scope', '$http', '$templateCache',
10251               function($scope, $http, $templateCache) {
10252                 $scope.method = 'GET';
10253                 $scope.url = 'http-hello.html';
10254
10255                 $scope.fetch = function() {
10256                   $scope.code = null;
10257                   $scope.response = null;
10258
10259                   $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
10260                     then(function(response) {
10261                       $scope.status = response.status;
10262                       $scope.data = response.data;
10263                     }, function(response) {
10264                       $scope.data = response.data || "Request failed";
10265                       $scope.status = response.status;
10266                   });
10267                 };
10268
10269                 $scope.updateModel = function(method, url) {
10270                   $scope.method = method;
10271                   $scope.url = url;
10272                 };
10273               }]);
10274         </file>
10275         <file name="http-hello.html">
10276           Hello, $http!
10277         </file>
10278         <file name="protractor.js" type="protractor">
10279           var status = element(by.binding('status'));
10280           var data = element(by.binding('data'));
10281           var fetchBtn = element(by.id('fetchbtn'));
10282           var sampleGetBtn = element(by.id('samplegetbtn'));
10283           var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
10284           var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
10285
10286           it('should make an xhr GET request', function() {
10287             sampleGetBtn.click();
10288             fetchBtn.click();
10289             expect(status.getText()).toMatch('200');
10290             expect(data.getText()).toMatch(/Hello, \$http!/);
10291           });
10292
10293         // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
10294         // it('should make a JSONP request to angularjs.org', function() {
10295         //   sampleJsonpBtn.click();
10296         //   fetchBtn.click();
10297         //   expect(status.getText()).toMatch('200');
10298         //   expect(data.getText()).toMatch(/Super Hero!/);
10299         // });
10300
10301           it('should make JSONP request to invalid URL and invoke the error handler',
10302               function() {
10303             invalidJsonpBtn.click();
10304             fetchBtn.click();
10305             expect(status.getText()).toMatch('0');
10306             expect(data.getText()).toMatch('Request failed');
10307           });
10308         </file>
10309         </example>
10310              */
10311             function $http(requestConfig) {
10312
10313               if (!angular.isObject(requestConfig)) {
10314                 throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
10315               }
10316
10317               var config = extend({
10318                 method: 'get',
10319                 transformRequest: defaults.transformRequest,
10320                 transformResponse: defaults.transformResponse,
10321                 paramSerializer: defaults.paramSerializer
10322               }, requestConfig);
10323
10324               config.headers = mergeHeaders(requestConfig);
10325               config.method = uppercase(config.method);
10326               config.paramSerializer = isString(config.paramSerializer) ?
10327                 $injector.get(config.paramSerializer) : config.paramSerializer;
10328
10329               var serverRequest = function(config) {
10330                 var headers = config.headers;
10331                 var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
10332
10333                 // strip content-type if data is undefined
10334                 if (isUndefined(reqData)) {
10335                   forEach(headers, function(value, header) {
10336                     if (lowercase(header) === 'content-type') {
10337                         delete headers[header];
10338                     }
10339                   });
10340                 }
10341
10342                 if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
10343                   config.withCredentials = defaults.withCredentials;
10344                 }
10345
10346                 // send request
10347                 return sendReq(config, reqData).then(transformResponse, transformResponse);
10348               };
10349
10350               var chain = [serverRequest, undefined];
10351               var promise = $q.when(config);
10352
10353               // apply interceptors
10354               forEach(reversedInterceptors, function(interceptor) {
10355                 if (interceptor.request || interceptor.requestError) {
10356                   chain.unshift(interceptor.request, interceptor.requestError);
10357                 }
10358                 if (interceptor.response || interceptor.responseError) {
10359                   chain.push(interceptor.response, interceptor.responseError);
10360                 }
10361               });
10362
10363               while (chain.length) {
10364                 var thenFn = chain.shift();
10365                 var rejectFn = chain.shift();
10366
10367                 promise = promise.then(thenFn, rejectFn);
10368               }
10369
10370               if (useLegacyPromise) {
10371                 promise.success = function(fn) {
10372                   assertArgFn(fn, 'fn');
10373
10374                   promise.then(function(response) {
10375                     fn(response.data, response.status, response.headers, config);
10376                   });
10377                   return promise;
10378                 };
10379
10380                 promise.error = function(fn) {
10381                   assertArgFn(fn, 'fn');
10382
10383                   promise.then(null, function(response) {
10384                     fn(response.data, response.status, response.headers, config);
10385                   });
10386                   return promise;
10387                 };
10388               } else {
10389                 promise.success = $httpMinErrLegacyFn('success');
10390                 promise.error = $httpMinErrLegacyFn('error');
10391               }
10392
10393               return promise;
10394
10395               function transformResponse(response) {
10396                 // make a copy since the response must be cacheable
10397                 var resp = extend({}, response);
10398                 resp.data = transformData(response.data, response.headers, response.status,
10399                                           config.transformResponse);
10400                 return (isSuccess(response.status))
10401                   ? resp
10402                   : $q.reject(resp);
10403               }
10404
10405               function executeHeaderFns(headers, config) {
10406                 var headerContent, processedHeaders = {};
10407
10408                 forEach(headers, function(headerFn, header) {
10409                   if (isFunction(headerFn)) {
10410                     headerContent = headerFn(config);
10411                     if (headerContent != null) {
10412                       processedHeaders[header] = headerContent;
10413                     }
10414                   } else {
10415                     processedHeaders[header] = headerFn;
10416                   }
10417                 });
10418
10419                 return processedHeaders;
10420               }
10421
10422               function mergeHeaders(config) {
10423                 var defHeaders = defaults.headers,
10424                     reqHeaders = extend({}, config.headers),
10425                     defHeaderName, lowercaseDefHeaderName, reqHeaderName;
10426
10427                 defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
10428
10429                 // using for-in instead of forEach to avoid unecessary iteration after header has been found
10430                 defaultHeadersIteration:
10431                 for (defHeaderName in defHeaders) {
10432                   lowercaseDefHeaderName = lowercase(defHeaderName);
10433
10434                   for (reqHeaderName in reqHeaders) {
10435                     if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
10436                       continue defaultHeadersIteration;
10437                     }
10438                   }
10439
10440                   reqHeaders[defHeaderName] = defHeaders[defHeaderName];
10441                 }
10442
10443                 // execute if header value is a function for merged headers
10444                 return executeHeaderFns(reqHeaders, shallowCopy(config));
10445               }
10446             }
10447
10448             $http.pendingRequests = [];
10449
10450             /**
10451              * @ngdoc method
10452              * @name $http#get
10453              *
10454              * @description
10455              * Shortcut method to perform `GET` request.
10456              *
10457              * @param {string} url Relative or absolute URL specifying the destination of the request
10458              * @param {Object=} config Optional configuration object
10459              * @returns {HttpPromise} Future object
10460              */
10461
10462             /**
10463              * @ngdoc method
10464              * @name $http#delete
10465              *
10466              * @description
10467              * Shortcut method to perform `DELETE` request.
10468              *
10469              * @param {string} url Relative or absolute URL specifying the destination of the request
10470              * @param {Object=} config Optional configuration object
10471              * @returns {HttpPromise} Future object
10472              */
10473
10474             /**
10475              * @ngdoc method
10476              * @name $http#head
10477              *
10478              * @description
10479              * Shortcut method to perform `HEAD` request.
10480              *
10481              * @param {string} url Relative or absolute URL specifying the destination of the request
10482              * @param {Object=} config Optional configuration object
10483              * @returns {HttpPromise} Future object
10484              */
10485
10486             /**
10487              * @ngdoc method
10488              * @name $http#jsonp
10489              *
10490              * @description
10491              * Shortcut method to perform `JSONP` request.
10492              *
10493              * @param {string} url Relative or absolute URL specifying the destination of the request.
10494              *                     The name of the callback should be the string `JSON_CALLBACK`.
10495              * @param {Object=} config Optional configuration object
10496              * @returns {HttpPromise} Future object
10497              */
10498             createShortMethods('get', 'delete', 'head', 'jsonp');
10499
10500             /**
10501              * @ngdoc method
10502              * @name $http#post
10503              *
10504              * @description
10505              * Shortcut method to perform `POST` request.
10506              *
10507              * @param {string} url Relative or absolute URL specifying the destination of the request
10508              * @param {*} data Request content
10509              * @param {Object=} config Optional configuration object
10510              * @returns {HttpPromise} Future object
10511              */
10512
10513             /**
10514              * @ngdoc method
10515              * @name $http#put
10516              *
10517              * @description
10518              * Shortcut method to perform `PUT` request.
10519              *
10520              * @param {string} url Relative or absolute URL specifying the destination of the request
10521              * @param {*} data Request content
10522              * @param {Object=} config Optional configuration object
10523              * @returns {HttpPromise} Future object
10524              */
10525
10526              /**
10527               * @ngdoc method
10528               * @name $http#patch
10529               *
10530               * @description
10531               * Shortcut method to perform `PATCH` request.
10532               *
10533               * @param {string} url Relative or absolute URL specifying the destination of the request
10534               * @param {*} data Request content
10535               * @param {Object=} config Optional configuration object
10536               * @returns {HttpPromise} Future object
10537               */
10538             createShortMethodsWithData('post', 'put', 'patch');
10539
10540                 /**
10541                  * @ngdoc property
10542                  * @name $http#defaults
10543                  *
10544                  * @description
10545                  * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
10546                  * default headers, withCredentials as well as request and response transformations.
10547                  *
10548                  * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
10549                  */
10550             $http.defaults = defaults;
10551
10552
10553             return $http;
10554
10555
10556             function createShortMethods(names) {
10557               forEach(arguments, function(name) {
10558                 $http[name] = function(url, config) {
10559                   return $http(extend({}, config || {}, {
10560                     method: name,
10561                     url: url
10562                   }));
10563                 };
10564               });
10565             }
10566
10567
10568             function createShortMethodsWithData(name) {
10569               forEach(arguments, function(name) {
10570                 $http[name] = function(url, data, config) {
10571                   return $http(extend({}, config || {}, {
10572                     method: name,
10573                     url: url,
10574                     data: data
10575                   }));
10576                 };
10577               });
10578             }
10579
10580
10581             /**
10582              * Makes the request.
10583              *
10584              * !!! ACCESSES CLOSURE VARS:
10585              * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
10586              */
10587             function sendReq(config, reqData) {
10588               var deferred = $q.defer(),
10589                   promise = deferred.promise,
10590                   cache,
10591                   cachedResp,
10592                   reqHeaders = config.headers,
10593                   url = buildUrl(config.url, config.paramSerializer(config.params));
10594
10595               $http.pendingRequests.push(config);
10596               promise.then(removePendingReq, removePendingReq);
10597
10598
10599               if ((config.cache || defaults.cache) && config.cache !== false &&
10600                   (config.method === 'GET' || config.method === 'JSONP')) {
10601                 cache = isObject(config.cache) ? config.cache
10602                       : isObject(defaults.cache) ? defaults.cache
10603                       : defaultCache;
10604               }
10605
10606               if (cache) {
10607                 cachedResp = cache.get(url);
10608                 if (isDefined(cachedResp)) {
10609                   if (isPromiseLike(cachedResp)) {
10610                     // cached request has already been sent, but there is no response yet
10611                     cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
10612                   } else {
10613                     // serving from cache
10614                     if (isArray(cachedResp)) {
10615                       resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
10616                     } else {
10617                       resolvePromise(cachedResp, 200, {}, 'OK');
10618                     }
10619                   }
10620                 } else {
10621                   // put the promise for the non-transformed response into cache as a placeholder
10622                   cache.put(url, promise);
10623                 }
10624               }
10625
10626
10627               // if we won't have the response in cache, set the xsrf headers and
10628               // send the request to the backend
10629               if (isUndefined(cachedResp)) {
10630                 var xsrfValue = urlIsSameOrigin(config.url)
10631                     ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
10632                     : undefined;
10633                 if (xsrfValue) {
10634                   reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
10635                 }
10636
10637                 $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
10638                     config.withCredentials, config.responseType);
10639               }
10640
10641               return promise;
10642
10643
10644               /**
10645                * Callback registered to $httpBackend():
10646                *  - caches the response if desired
10647                *  - resolves the raw $http promise
10648                *  - calls $apply
10649                */
10650               function done(status, response, headersString, statusText) {
10651                 if (cache) {
10652                   if (isSuccess(status)) {
10653                     cache.put(url, [status, response, parseHeaders(headersString), statusText]);
10654                   } else {
10655                     // remove promise from the cache
10656                     cache.remove(url);
10657                   }
10658                 }
10659
10660                 function resolveHttpPromise() {
10661                   resolvePromise(response, status, headersString, statusText);
10662                 }
10663
10664                 if (useApplyAsync) {
10665                   $rootScope.$applyAsync(resolveHttpPromise);
10666                 } else {
10667                   resolveHttpPromise();
10668                   if (!$rootScope.$$phase) $rootScope.$apply();
10669                 }
10670               }
10671
10672
10673               /**
10674                * Resolves the raw $http promise.
10675                */
10676               function resolvePromise(response, status, headers, statusText) {
10677                 //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
10678                 status = status >= -1 ? status : 0;
10679
10680                 (isSuccess(status) ? deferred.resolve : deferred.reject)({
10681                   data: response,
10682                   status: status,
10683                   headers: headersGetter(headers),
10684                   config: config,
10685                   statusText: statusText
10686                 });
10687               }
10688
10689               function resolvePromiseWithResult(result) {
10690                 resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
10691               }
10692
10693               function removePendingReq() {
10694                 var idx = $http.pendingRequests.indexOf(config);
10695                 if (idx !== -1) $http.pendingRequests.splice(idx, 1);
10696               }
10697             }
10698
10699
10700             function buildUrl(url, serializedParams) {
10701               if (serializedParams.length > 0) {
10702                 url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
10703               }
10704               return url;
10705             }
10706           }];
10707         }
10708
10709         /**
10710          * @ngdoc service
10711          * @name $xhrFactory
10712          *
10713          * @description
10714          * Factory function used to create XMLHttpRequest objects.
10715          *
10716          * Replace or decorate this service to create your own custom XMLHttpRequest objects.
10717          *
10718          * ```
10719          * angular.module('myApp', [])
10720          * .factory('$xhrFactory', function() {
10721          *   return function createXhr(method, url) {
10722          *     return new window.XMLHttpRequest({mozSystem: true});
10723          *   };
10724          * });
10725          * ```
10726          *
10727          * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
10728          * @param {string} url URL of the request.
10729          */
10730         function $xhrFactoryProvider() {
10731           this.$get = function() {
10732             return function createXhr() {
10733               return new window.XMLHttpRequest();
10734             };
10735           };
10736         }
10737
10738         /**
10739          * @ngdoc service
10740          * @name $httpBackend
10741          * @requires $window
10742          * @requires $document
10743          * @requires $xhrFactory
10744          *
10745          * @description
10746          * HTTP backend used by the {@link ng.$http service} that delegates to
10747          * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
10748          *
10749          * You should never need to use this service directly, instead use the higher-level abstractions:
10750          * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
10751          *
10752          * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
10753          * $httpBackend} which can be trained with responses.
10754          */
10755         function $HttpBackendProvider() {
10756           this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
10757             return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
10758           }];
10759         }
10760
10761         function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
10762           // TODO(vojta): fix the signature
10763           return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
10764             $browser.$$incOutstandingRequestCount();
10765             url = url || $browser.url();
10766
10767             if (lowercase(method) == 'jsonp') {
10768               var callbackId = '_' + (callbacks.counter++).toString(36);
10769               callbacks[callbackId] = function(data) {
10770                 callbacks[callbackId].data = data;
10771                 callbacks[callbackId].called = true;
10772               };
10773
10774               var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
10775                   callbackId, function(status, text) {
10776                 completeRequest(callback, status, callbacks[callbackId].data, "", text);
10777                 callbacks[callbackId] = noop;
10778               });
10779             } else {
10780
10781               var xhr = createXhr(method, url);
10782
10783               xhr.open(method, url, true);
10784               forEach(headers, function(value, key) {
10785                 if (isDefined(value)) {
10786                     xhr.setRequestHeader(key, value);
10787                 }
10788               });
10789
10790               xhr.onload = function requestLoaded() {
10791                 var statusText = xhr.statusText || '';
10792
10793                 // responseText is the old-school way of retrieving response (supported by IE9)
10794                 // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
10795                 var response = ('response' in xhr) ? xhr.response : xhr.responseText;
10796
10797                 // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
10798                 var status = xhr.status === 1223 ? 204 : xhr.status;
10799
10800                 // fix status code when it is 0 (0 status is undocumented).
10801                 // Occurs when accessing file resources or on Android 4.1 stock browser
10802                 // while retrieving files from application cache.
10803                 if (status === 0) {
10804                   status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
10805                 }
10806
10807                 completeRequest(callback,
10808                     status,
10809                     response,
10810                     xhr.getAllResponseHeaders(),
10811                     statusText);
10812               };
10813
10814               var requestError = function() {
10815                 // The response is always empty
10816                 // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
10817                 completeRequest(callback, -1, null, null, '');
10818               };
10819
10820               xhr.onerror = requestError;
10821               xhr.onabort = requestError;
10822
10823               if (withCredentials) {
10824                 xhr.withCredentials = true;
10825               }
10826
10827               if (responseType) {
10828                 try {
10829                   xhr.responseType = responseType;
10830                 } catch (e) {
10831                   // WebKit added support for the json responseType value on 09/03/2013
10832                   // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
10833                   // known to throw when setting the value "json" as the response type. Other older
10834                   // browsers implementing the responseType
10835                   //
10836                   // The json response type can be ignored if not supported, because JSON payloads are
10837                   // parsed on the client-side regardless.
10838                   if (responseType !== 'json') {
10839                     throw e;
10840                   }
10841                 }
10842               }
10843
10844               xhr.send(isUndefined(post) ? null : post);
10845             }
10846
10847             if (timeout > 0) {
10848               var timeoutId = $browserDefer(timeoutRequest, timeout);
10849             } else if (isPromiseLike(timeout)) {
10850               timeout.then(timeoutRequest);
10851             }
10852
10853
10854             function timeoutRequest() {
10855               jsonpDone && jsonpDone();
10856               xhr && xhr.abort();
10857             }
10858
10859             function completeRequest(callback, status, response, headersString, statusText) {
10860               // cancel timeout and subsequent timeout promise resolution
10861               if (isDefined(timeoutId)) {
10862                 $browserDefer.cancel(timeoutId);
10863               }
10864               jsonpDone = xhr = null;
10865
10866               callback(status, response, headersString, statusText);
10867               $browser.$$completeOutstandingRequest(noop);
10868             }
10869           };
10870
10871           function jsonpReq(url, callbackId, done) {
10872             // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
10873             // - fetches local scripts via XHR and evals them
10874             // - adds and immediately removes script elements from the document
10875             var script = rawDocument.createElement('script'), callback = null;
10876             script.type = "text/javascript";
10877             script.src = url;
10878             script.async = true;
10879
10880             callback = function(event) {
10881               removeEventListenerFn(script, "load", callback);
10882               removeEventListenerFn(script, "error", callback);
10883               rawDocument.body.removeChild(script);
10884               script = null;
10885               var status = -1;
10886               var text = "unknown";
10887
10888               if (event) {
10889                 if (event.type === "load" && !callbacks[callbackId].called) {
10890                   event = { type: "error" };
10891                 }
10892                 text = event.type;
10893                 status = event.type === "error" ? 404 : 200;
10894               }
10895
10896               if (done) {
10897                 done(status, text);
10898               }
10899             };
10900
10901             addEventListenerFn(script, "load", callback);
10902             addEventListenerFn(script, "error", callback);
10903             rawDocument.body.appendChild(script);
10904             return callback;
10905           }
10906         }
10907
10908         var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
10909         $interpolateMinErr.throwNoconcat = function(text) {
10910           throw $interpolateMinErr('noconcat',
10911               "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
10912               "interpolations that concatenate multiple expressions when a trusted value is " +
10913               "required.  See http://docs.angularjs.org/api/ng.$sce", text);
10914         };
10915
10916         $interpolateMinErr.interr = function(text, err) {
10917           return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
10918         };
10919
10920         /**
10921          * @ngdoc provider
10922          * @name $interpolateProvider
10923          *
10924          * @description
10925          *
10926          * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
10927          *
10928          * @example
10929         <example module="customInterpolationApp">
10930         <file name="index.html">
10931         <script>
10932           var customInterpolationApp = angular.module('customInterpolationApp', []);
10933
10934           customInterpolationApp.config(function($interpolateProvider) {
10935             $interpolateProvider.startSymbol('//');
10936             $interpolateProvider.endSymbol('//');
10937           });
10938
10939
10940           customInterpolationApp.controller('DemoController', function() {
10941               this.label = "This binding is brought you by // interpolation symbols.";
10942           });
10943         </script>
10944         <div ng-app="App" ng-controller="DemoController as demo">
10945             //demo.label//
10946         </div>
10947         </file>
10948         <file name="protractor.js" type="protractor">
10949           it('should interpolate binding with custom symbols', function() {
10950             expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
10951           });
10952         </file>
10953         </example>
10954          */
10955         function $InterpolateProvider() {
10956           var startSymbol = '{{';
10957           var endSymbol = '}}';
10958
10959           /**
10960            * @ngdoc method
10961            * @name $interpolateProvider#startSymbol
10962            * @description
10963            * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
10964            *
10965            * @param {string=} value new value to set the starting symbol to.
10966            * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10967            */
10968           this.startSymbol = function(value) {
10969             if (value) {
10970               startSymbol = value;
10971               return this;
10972             } else {
10973               return startSymbol;
10974             }
10975           };
10976
10977           /**
10978            * @ngdoc method
10979            * @name $interpolateProvider#endSymbol
10980            * @description
10981            * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10982            *
10983            * @param {string=} value new value to set the ending symbol to.
10984            * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10985            */
10986           this.endSymbol = function(value) {
10987             if (value) {
10988               endSymbol = value;
10989               return this;
10990             } else {
10991               return endSymbol;
10992             }
10993           };
10994
10995
10996           this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
10997             var startSymbolLength = startSymbol.length,
10998                 endSymbolLength = endSymbol.length,
10999                 escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
11000                 escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
11001
11002             function escape(ch) {
11003               return '\\\\\\' + ch;
11004             }
11005
11006             function unescapeText(text) {
11007               return text.replace(escapedStartRegexp, startSymbol).
11008                 replace(escapedEndRegexp, endSymbol);
11009             }
11010
11011             function stringify(value) {
11012               if (value == null) { // null || undefined
11013                 return '';
11014               }
11015               switch (typeof value) {
11016                 case 'string':
11017                   break;
11018                 case 'number':
11019                   value = '' + value;
11020                   break;
11021                 default:
11022                   value = toJson(value);
11023               }
11024
11025               return value;
11026             }
11027
11028             /**
11029              * @ngdoc service
11030              * @name $interpolate
11031              * @kind function
11032              *
11033              * @requires $parse
11034              * @requires $sce
11035              *
11036              * @description
11037              *
11038              * Compiles a string with markup into an interpolation function. This service is used by the
11039              * HTML {@link ng.$compile $compile} service for data binding. See
11040              * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
11041              * interpolation markup.
11042              *
11043              *
11044              * ```js
11045              *   var $interpolate = ...; // injected
11046              *   var exp = $interpolate('Hello {{name | uppercase}}!');
11047              *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
11048              * ```
11049              *
11050              * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
11051              * `true`, the interpolation function will return `undefined` unless all embedded expressions
11052              * evaluate to a value other than `undefined`.
11053              *
11054              * ```js
11055              *   var $interpolate = ...; // injected
11056              *   var context = {greeting: 'Hello', name: undefined };
11057              *
11058              *   // default "forgiving" mode
11059              *   var exp = $interpolate('{{greeting}} {{name}}!');
11060              *   expect(exp(context)).toEqual('Hello !');
11061              *
11062              *   // "allOrNothing" mode
11063              *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
11064              *   expect(exp(context)).toBeUndefined();
11065              *   context.name = 'Angular';
11066              *   expect(exp(context)).toEqual('Hello Angular!');
11067              * ```
11068              *
11069              * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
11070              *
11071              * ####Escaped Interpolation
11072              * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
11073              * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
11074              * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
11075              * or binding.
11076              *
11077              * This enables web-servers to prevent script injection attacks and defacing attacks, to some
11078              * degree, while also enabling code examples to work without relying on the
11079              * {@link ng.directive:ngNonBindable ngNonBindable} directive.
11080              *
11081              * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
11082              * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
11083              * interpolation start/end markers with their escaped counterparts.**
11084              *
11085              * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
11086              * output when the $interpolate service processes the text. So, for HTML elements interpolated
11087              * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
11088              * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
11089              * this is typically useful only when user-data is used in rendering a template from the server, or
11090              * when otherwise untrusted data is used by a directive.
11091              *
11092              * <example>
11093              *  <file name="index.html">
11094              *    <div ng-init="username='A user'">
11095              *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
11096              *        </p>
11097              *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
11098              *        application, but fails to accomplish their task, because the server has correctly
11099              *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
11100              *        characters.</p>
11101              *      <p>Instead, the result of the attempted script injection is visible, and can be removed
11102              *        from the database by an administrator.</p>
11103              *    </div>
11104              *  </file>
11105              * </example>
11106              *
11107              * @param {string} text The text with markup to interpolate.
11108              * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
11109              *    embedded expression in order to return an interpolation function. Strings with no
11110              *    embedded expression will return null for the interpolation function.
11111              * @param {string=} trustedContext when provided, the returned function passes the interpolated
11112              *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
11113              *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
11114              *    provides Strict Contextual Escaping for details.
11115              * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
11116              *    unless all embedded expressions evaluate to a value other than `undefined`.
11117              * @returns {function(context)} an interpolation function which is used to compute the
11118              *    interpolated string. The function has these parameters:
11119              *
11120              * - `context`: evaluation context for all expressions embedded in the interpolated text
11121              */
11122             function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
11123               allOrNothing = !!allOrNothing;
11124               var startIndex,
11125                   endIndex,
11126                   index = 0,
11127                   expressions = [],
11128                   parseFns = [],
11129                   textLength = text.length,
11130                   exp,
11131                   concat = [],
11132                   expressionPositions = [];
11133
11134               while (index < textLength) {
11135                 if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
11136                      ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
11137                   if (index !== startIndex) {
11138                     concat.push(unescapeText(text.substring(index, startIndex)));
11139                   }
11140                   exp = text.substring(startIndex + startSymbolLength, endIndex);
11141                   expressions.push(exp);
11142                   parseFns.push($parse(exp, parseStringifyInterceptor));
11143                   index = endIndex + endSymbolLength;
11144                   expressionPositions.push(concat.length);
11145                   concat.push('');
11146                 } else {
11147                   // we did not find an interpolation, so we have to add the remainder to the separators array
11148                   if (index !== textLength) {
11149                     concat.push(unescapeText(text.substring(index)));
11150                   }
11151                   break;
11152                 }
11153               }
11154
11155               // Concatenating expressions makes it hard to reason about whether some combination of
11156               // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
11157               // single expression be used for iframe[src], object[src], etc., we ensure that the value
11158               // that's used is assigned or constructed by some JS code somewhere that is more testable or
11159               // make it obvious that you bound the value to some user controlled value.  This helps reduce
11160               // the load when auditing for XSS issues.
11161               if (trustedContext && concat.length > 1) {
11162                   $interpolateMinErr.throwNoconcat(text);
11163               }
11164
11165               if (!mustHaveExpression || expressions.length) {
11166                 var compute = function(values) {
11167                   for (var i = 0, ii = expressions.length; i < ii; i++) {
11168                     if (allOrNothing && isUndefined(values[i])) return;
11169                     concat[expressionPositions[i]] = values[i];
11170                   }
11171                   return concat.join('');
11172                 };
11173
11174                 var getValue = function(value) {
11175                   return trustedContext ?
11176                     $sce.getTrusted(trustedContext, value) :
11177                     $sce.valueOf(value);
11178                 };
11179
11180                 return extend(function interpolationFn(context) {
11181                     var i = 0;
11182                     var ii = expressions.length;
11183                     var values = new Array(ii);
11184
11185                     try {
11186                       for (; i < ii; i++) {
11187                         values[i] = parseFns[i](context);
11188                       }
11189
11190                       return compute(values);
11191                     } catch (err) {
11192                       $exceptionHandler($interpolateMinErr.interr(text, err));
11193                     }
11194
11195                   }, {
11196                   // all of these properties are undocumented for now
11197                   exp: text, //just for compatibility with regular watchers created via $watch
11198                   expressions: expressions,
11199                   $$watchDelegate: function(scope, listener) {
11200                     var lastValue;
11201                     return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
11202                       var currValue = compute(values);
11203                       if (isFunction(listener)) {
11204                         listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
11205                       }
11206                       lastValue = currValue;
11207                     });
11208                   }
11209                 });
11210               }
11211
11212               function parseStringifyInterceptor(value) {
11213                 try {
11214                   value = getValue(value);
11215                   return allOrNothing && !isDefined(value) ? value : stringify(value);
11216                 } catch (err) {
11217                   $exceptionHandler($interpolateMinErr.interr(text, err));
11218                 }
11219               }
11220             }
11221
11222
11223             /**
11224              * @ngdoc method
11225              * @name $interpolate#startSymbol
11226              * @description
11227              * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
11228              *
11229              * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
11230              * the symbol.
11231              *
11232              * @returns {string} start symbol.
11233              */
11234             $interpolate.startSymbol = function() {
11235               return startSymbol;
11236             };
11237
11238
11239             /**
11240              * @ngdoc method
11241              * @name $interpolate#endSymbol
11242              * @description
11243              * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
11244              *
11245              * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
11246              * the symbol.
11247              *
11248              * @returns {string} end symbol.
11249              */
11250             $interpolate.endSymbol = function() {
11251               return endSymbol;
11252             };
11253
11254             return $interpolate;
11255           }];
11256         }
11257
11258         function $IntervalProvider() {
11259           this.$get = ['$rootScope', '$window', '$q', '$$q',
11260                function($rootScope,   $window,   $q,   $$q) {
11261             var intervals = {};
11262
11263
11264              /**
11265               * @ngdoc service
11266               * @name $interval
11267               *
11268               * @description
11269               * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
11270               * milliseconds.
11271               *
11272               * The return value of registering an interval function is a promise. This promise will be
11273               * notified upon each tick of the interval, and will be resolved after `count` iterations, or
11274               * run indefinitely if `count` is not defined. The value of the notification will be the
11275               * number of iterations that have run.
11276               * To cancel an interval, call `$interval.cancel(promise)`.
11277               *
11278               * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
11279               * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
11280               * time.
11281               *
11282               * <div class="alert alert-warning">
11283               * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
11284               * with them.  In particular they are not automatically destroyed when a controller's scope or a
11285               * directive's element are destroyed.
11286               * You should take this into consideration and make sure to always cancel the interval at the
11287               * appropriate moment.  See the example below for more details on how and when to do this.
11288               * </div>
11289               *
11290               * @param {function()} fn A function that should be called repeatedly.
11291               * @param {number} delay Number of milliseconds between each function call.
11292               * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
11293               *   indefinitely.
11294               * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
11295               *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
11296               * @param {...*=} Pass additional parameters to the executed function.
11297               * @returns {promise} A promise which will be notified on each iteration.
11298               *
11299               * @example
11300               * <example module="intervalExample">
11301               * <file name="index.html">
11302               *   <script>
11303               *     angular.module('intervalExample', [])
11304               *       .controller('ExampleController', ['$scope', '$interval',
11305               *         function($scope, $interval) {
11306               *           $scope.format = 'M/d/yy h:mm:ss a';
11307               *           $scope.blood_1 = 100;
11308               *           $scope.blood_2 = 120;
11309               *
11310               *           var stop;
11311               *           $scope.fight = function() {
11312               *             // Don't start a new fight if we are already fighting
11313               *             if ( angular.isDefined(stop) ) return;
11314               *
11315               *             stop = $interval(function() {
11316               *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
11317               *                 $scope.blood_1 = $scope.blood_1 - 3;
11318               *                 $scope.blood_2 = $scope.blood_2 - 4;
11319               *               } else {
11320               *                 $scope.stopFight();
11321               *               }
11322               *             }, 100);
11323               *           };
11324               *
11325               *           $scope.stopFight = function() {
11326               *             if (angular.isDefined(stop)) {
11327               *               $interval.cancel(stop);
11328               *               stop = undefined;
11329               *             }
11330               *           };
11331               *
11332               *           $scope.resetFight = function() {
11333               *             $scope.blood_1 = 100;
11334               *             $scope.blood_2 = 120;
11335               *           };
11336               *
11337               *           $scope.$on('$destroy', function() {
11338               *             // Make sure that the interval is destroyed too
11339               *             $scope.stopFight();
11340               *           });
11341               *         }])
11342               *       // Register the 'myCurrentTime' directive factory method.
11343               *       // We inject $interval and dateFilter service since the factory method is DI.
11344               *       .directive('myCurrentTime', ['$interval', 'dateFilter',
11345               *         function($interval, dateFilter) {
11346               *           // return the directive link function. (compile function not needed)
11347               *           return function(scope, element, attrs) {
11348               *             var format,  // date format
11349               *                 stopTime; // so that we can cancel the time updates
11350               *
11351               *             // used to update the UI
11352               *             function updateTime() {
11353               *               element.text(dateFilter(new Date(), format));
11354               *             }
11355               *
11356               *             // watch the expression, and update the UI on change.
11357               *             scope.$watch(attrs.myCurrentTime, function(value) {
11358               *               format = value;
11359               *               updateTime();
11360               *             });
11361               *
11362               *             stopTime = $interval(updateTime, 1000);
11363               *
11364               *             // listen on DOM destroy (removal) event, and cancel the next UI update
11365               *             // to prevent updating time after the DOM element was removed.
11366               *             element.on('$destroy', function() {
11367               *               $interval.cancel(stopTime);
11368               *             });
11369               *           }
11370               *         }]);
11371               *   </script>
11372               *
11373               *   <div>
11374               *     <div ng-controller="ExampleController">
11375               *       <label>Date format: <input ng-model="format"></label> <hr/>
11376               *       Current time is: <span my-current-time="format"></span>
11377               *       <hr/>
11378               *       Blood 1 : <font color='red'>{{blood_1}}</font>
11379               *       Blood 2 : <font color='red'>{{blood_2}}</font>
11380               *       <button type="button" data-ng-click="fight()">Fight</button>
11381               *       <button type="button" data-ng-click="stopFight()">StopFight</button>
11382               *       <button type="button" data-ng-click="resetFight()">resetFight</button>
11383               *     </div>
11384               *   </div>
11385               *
11386               * </file>
11387               * </example>
11388               */
11389             function interval(fn, delay, count, invokeApply) {
11390               var hasParams = arguments.length > 4,
11391                   args = hasParams ? sliceArgs(arguments, 4) : [],
11392                   setInterval = $window.setInterval,
11393                   clearInterval = $window.clearInterval,
11394                   iteration = 0,
11395                   skipApply = (isDefined(invokeApply) && !invokeApply),
11396                   deferred = (skipApply ? $$q : $q).defer(),
11397                   promise = deferred.promise;
11398
11399               count = isDefined(count) ? count : 0;
11400
11401               promise.then(null, null, (!hasParams) ? fn : function() {
11402                 fn.apply(null, args);
11403               });
11404
11405               promise.$$intervalId = setInterval(function tick() {
11406                 deferred.notify(iteration++);
11407
11408                 if (count > 0 && iteration >= count) {
11409                   deferred.resolve(iteration);
11410                   clearInterval(promise.$$intervalId);
11411                   delete intervals[promise.$$intervalId];
11412                 }
11413
11414                 if (!skipApply) $rootScope.$apply();
11415
11416               }, delay);
11417
11418               intervals[promise.$$intervalId] = deferred;
11419
11420               return promise;
11421             }
11422
11423
11424              /**
11425               * @ngdoc method
11426               * @name $interval#cancel
11427               *
11428               * @description
11429               * Cancels a task associated with the `promise`.
11430               *
11431               * @param {Promise=} promise returned by the `$interval` function.
11432               * @returns {boolean} Returns `true` if the task was successfully canceled.
11433               */
11434             interval.cancel = function(promise) {
11435               if (promise && promise.$$intervalId in intervals) {
11436                 intervals[promise.$$intervalId].reject('canceled');
11437                 $window.clearInterval(promise.$$intervalId);
11438                 delete intervals[promise.$$intervalId];
11439                 return true;
11440               }
11441               return false;
11442             };
11443
11444             return interval;
11445           }];
11446         }
11447
11448         /**
11449          * @ngdoc service
11450          * @name $locale
11451          *
11452          * @description
11453          * $locale service provides localization rules for various Angular components. As of right now the
11454          * only public api is:
11455          *
11456          * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
11457          */
11458
11459         var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
11460             DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
11461         var $locationMinErr = minErr('$location');
11462
11463
11464         /**
11465          * Encode path using encodeUriSegment, ignoring forward slashes
11466          *
11467          * @param {string} path Path to encode
11468          * @returns {string}
11469          */
11470         function encodePath(path) {
11471           var segments = path.split('/'),
11472               i = segments.length;
11473
11474           while (i--) {
11475             segments[i] = encodeUriSegment(segments[i]);
11476           }
11477
11478           return segments.join('/');
11479         }
11480
11481         function parseAbsoluteUrl(absoluteUrl, locationObj) {
11482           var parsedUrl = urlResolve(absoluteUrl);
11483
11484           locationObj.$$protocol = parsedUrl.protocol;
11485           locationObj.$$host = parsedUrl.hostname;
11486           locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
11487         }
11488
11489
11490         function parseAppUrl(relativeUrl, locationObj) {
11491           var prefixed = (relativeUrl.charAt(0) !== '/');
11492           if (prefixed) {
11493             relativeUrl = '/' + relativeUrl;
11494           }
11495           var match = urlResolve(relativeUrl);
11496           locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
11497               match.pathname.substring(1) : match.pathname);
11498           locationObj.$$search = parseKeyValue(match.search);
11499           locationObj.$$hash = decodeURIComponent(match.hash);
11500
11501           // make sure path starts with '/';
11502           if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
11503             locationObj.$$path = '/' + locationObj.$$path;
11504           }
11505         }
11506
11507
11508         /**
11509          *
11510          * @param {string} begin
11511          * @param {string} whole
11512          * @returns {string} returns text from whole after begin or undefined if it does not begin with
11513          *                   expected string.
11514          */
11515         function beginsWith(begin, whole) {
11516           if (whole.indexOf(begin) === 0) {
11517             return whole.substr(begin.length);
11518           }
11519         }
11520
11521
11522         function stripHash(url) {
11523           var index = url.indexOf('#');
11524           return index == -1 ? url : url.substr(0, index);
11525         }
11526
11527         function trimEmptyHash(url) {
11528           return url.replace(/(#.+)|#$/, '$1');
11529         }
11530
11531
11532         function stripFile(url) {
11533           return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
11534         }
11535
11536         /* return the server only (scheme://host:port) */
11537         function serverBase(url) {
11538           return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
11539         }
11540
11541
11542         /**
11543          * LocationHtml5Url represents an url
11544          * This object is exposed as $location service when HTML5 mode is enabled and supported
11545          *
11546          * @constructor
11547          * @param {string} appBase application base URL
11548          * @param {string} appBaseNoFile application base URL stripped of any filename
11549          * @param {string} basePrefix url path prefix
11550          */
11551         function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
11552           this.$$html5 = true;
11553           basePrefix = basePrefix || '';
11554           parseAbsoluteUrl(appBase, this);
11555
11556
11557           /**
11558            * Parse given html5 (regular) url string into properties
11559            * @param {string} url HTML5 url
11560            * @private
11561            */
11562           this.$$parse = function(url) {
11563             var pathUrl = beginsWith(appBaseNoFile, url);
11564             if (!isString(pathUrl)) {
11565               throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
11566                   appBaseNoFile);
11567             }
11568
11569             parseAppUrl(pathUrl, this);
11570
11571             if (!this.$$path) {
11572               this.$$path = '/';
11573             }
11574
11575             this.$$compose();
11576           };
11577
11578           /**
11579            * Compose url and update `absUrl` property
11580            * @private
11581            */
11582           this.$$compose = function() {
11583             var search = toKeyValue(this.$$search),
11584                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11585
11586             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11587             this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
11588           };
11589
11590           this.$$parseLinkUrl = function(url, relHref) {
11591             if (relHref && relHref[0] === '#') {
11592               // special case for links to hash fragments:
11593               // keep the old url and only replace the hash fragment
11594               this.hash(relHref.slice(1));
11595               return true;
11596             }
11597             var appUrl, prevAppUrl;
11598             var rewrittenUrl;
11599
11600             if (isDefined(appUrl = beginsWith(appBase, url))) {
11601               prevAppUrl = appUrl;
11602               if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
11603                 rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
11604               } else {
11605                 rewrittenUrl = appBase + prevAppUrl;
11606               }
11607             } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
11608               rewrittenUrl = appBaseNoFile + appUrl;
11609             } else if (appBaseNoFile == url + '/') {
11610               rewrittenUrl = appBaseNoFile;
11611             }
11612             if (rewrittenUrl) {
11613               this.$$parse(rewrittenUrl);
11614             }
11615             return !!rewrittenUrl;
11616           };
11617         }
11618
11619
11620         /**
11621          * LocationHashbangUrl represents url
11622          * This object is exposed as $location service when developer doesn't opt into html5 mode.
11623          * It also serves as the base class for html5 mode fallback on legacy browsers.
11624          *
11625          * @constructor
11626          * @param {string} appBase application base URL
11627          * @param {string} appBaseNoFile application base URL stripped of any filename
11628          * @param {string} hashPrefix hashbang prefix
11629          */
11630         function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
11631
11632           parseAbsoluteUrl(appBase, this);
11633
11634
11635           /**
11636            * Parse given hashbang url into properties
11637            * @param {string} url Hashbang url
11638            * @private
11639            */
11640           this.$$parse = function(url) {
11641             var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
11642             var withoutHashUrl;
11643
11644             if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
11645
11646               // The rest of the url starts with a hash so we have
11647               // got either a hashbang path or a plain hash fragment
11648               withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
11649               if (isUndefined(withoutHashUrl)) {
11650                 // There was no hashbang prefix so we just have a hash fragment
11651                 withoutHashUrl = withoutBaseUrl;
11652               }
11653
11654             } else {
11655               // There was no hashbang path nor hash fragment:
11656               // If we are in HTML5 mode we use what is left as the path;
11657               // Otherwise we ignore what is left
11658               if (this.$$html5) {
11659                 withoutHashUrl = withoutBaseUrl;
11660               } else {
11661                 withoutHashUrl = '';
11662                 if (isUndefined(withoutBaseUrl)) {
11663                   appBase = url;
11664                   this.replace();
11665                 }
11666               }
11667             }
11668
11669             parseAppUrl(withoutHashUrl, this);
11670
11671             this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
11672
11673             this.$$compose();
11674
11675             /*
11676              * In Windows, on an anchor node on documents loaded from
11677              * the filesystem, the browser will return a pathname
11678              * prefixed with the drive name ('/C:/path') when a
11679              * pathname without a drive is set:
11680              *  * a.setAttribute('href', '/foo')
11681              *   * a.pathname === '/C:/foo' //true
11682              *
11683              * Inside of Angular, we're always using pathnames that
11684              * do not include drive names for routing.
11685              */
11686             function removeWindowsDriveName(path, url, base) {
11687               /*
11688               Matches paths for file protocol on windows,
11689               such as /C:/foo/bar, and captures only /foo/bar.
11690               */
11691               var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
11692
11693               var firstPathSegmentMatch;
11694
11695               //Get the relative path from the input URL.
11696               if (url.indexOf(base) === 0) {
11697                 url = url.replace(base, '');
11698               }
11699
11700               // The input URL intentionally contains a first path segment that ends with a colon.
11701               if (windowsFilePathExp.exec(url)) {
11702                 return path;
11703               }
11704
11705               firstPathSegmentMatch = windowsFilePathExp.exec(path);
11706               return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
11707             }
11708           };
11709
11710           /**
11711            * Compose hashbang url and update `absUrl` property
11712            * @private
11713            */
11714           this.$$compose = function() {
11715             var search = toKeyValue(this.$$search),
11716                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11717
11718             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11719             this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
11720           };
11721
11722           this.$$parseLinkUrl = function(url, relHref) {
11723             if (stripHash(appBase) == stripHash(url)) {
11724               this.$$parse(url);
11725               return true;
11726             }
11727             return false;
11728           };
11729         }
11730
11731
11732         /**
11733          * LocationHashbangUrl represents url
11734          * This object is exposed as $location service when html5 history api is enabled but the browser
11735          * does not support it.
11736          *
11737          * @constructor
11738          * @param {string} appBase application base URL
11739          * @param {string} appBaseNoFile application base URL stripped of any filename
11740          * @param {string} hashPrefix hashbang prefix
11741          */
11742         function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
11743           this.$$html5 = true;
11744           LocationHashbangUrl.apply(this, arguments);
11745
11746           this.$$parseLinkUrl = function(url, relHref) {
11747             if (relHref && relHref[0] === '#') {
11748               // special case for links to hash fragments:
11749               // keep the old url and only replace the hash fragment
11750               this.hash(relHref.slice(1));
11751               return true;
11752             }
11753
11754             var rewrittenUrl;
11755             var appUrl;
11756
11757             if (appBase == stripHash(url)) {
11758               rewrittenUrl = url;
11759             } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
11760               rewrittenUrl = appBase + hashPrefix + appUrl;
11761             } else if (appBaseNoFile === url + '/') {
11762               rewrittenUrl = appBaseNoFile;
11763             }
11764             if (rewrittenUrl) {
11765               this.$$parse(rewrittenUrl);
11766             }
11767             return !!rewrittenUrl;
11768           };
11769
11770           this.$$compose = function() {
11771             var search = toKeyValue(this.$$search),
11772                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11773
11774             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11775             // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
11776             this.$$absUrl = appBase + hashPrefix + this.$$url;
11777           };
11778
11779         }
11780
11781
11782         var locationPrototype = {
11783
11784           /**
11785            * Are we in html5 mode?
11786            * @private
11787            */
11788           $$html5: false,
11789
11790           /**
11791            * Has any change been replacing?
11792            * @private
11793            */
11794           $$replace: false,
11795
11796           /**
11797            * @ngdoc method
11798            * @name $location#absUrl
11799            *
11800            * @description
11801            * This method is getter only.
11802            *
11803            * Return full url representation with all segments encoded according to rules specified in
11804            * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
11805            *
11806            *
11807            * ```js
11808            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11809            * var absUrl = $location.absUrl();
11810            * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
11811            * ```
11812            *
11813            * @return {string} full url
11814            */
11815           absUrl: locationGetter('$$absUrl'),
11816
11817           /**
11818            * @ngdoc method
11819            * @name $location#url
11820            *
11821            * @description
11822            * This method is getter / setter.
11823            *
11824            * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
11825            *
11826            * Change path, search and hash, when called with parameter and return `$location`.
11827            *
11828            *
11829            * ```js
11830            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11831            * var url = $location.url();
11832            * // => "/some/path?foo=bar&baz=xoxo"
11833            * ```
11834            *
11835            * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
11836            * @return {string} url
11837            */
11838           url: function(url) {
11839             if (isUndefined(url)) {
11840               return this.$$url;
11841             }
11842
11843             var match = PATH_MATCH.exec(url);
11844             if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
11845             if (match[2] || match[1] || url === '') this.search(match[3] || '');
11846             this.hash(match[5] || '');
11847
11848             return this;
11849           },
11850
11851           /**
11852            * @ngdoc method
11853            * @name $location#protocol
11854            *
11855            * @description
11856            * This method is getter only.
11857            *
11858            * Return protocol of current url.
11859            *
11860            *
11861            * ```js
11862            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11863            * var protocol = $location.protocol();
11864            * // => "http"
11865            * ```
11866            *
11867            * @return {string} protocol of current url
11868            */
11869           protocol: locationGetter('$$protocol'),
11870
11871           /**
11872            * @ngdoc method
11873            * @name $location#host
11874            *
11875            * @description
11876            * This method is getter only.
11877            *
11878            * Return host of current url.
11879            *
11880            * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
11881            *
11882            *
11883            * ```js
11884            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11885            * var host = $location.host();
11886            * // => "example.com"
11887            *
11888            * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
11889            * host = $location.host();
11890            * // => "example.com"
11891            * host = location.host;
11892            * // => "example.com:8080"
11893            * ```
11894            *
11895            * @return {string} host of current url.
11896            */
11897           host: locationGetter('$$host'),
11898
11899           /**
11900            * @ngdoc method
11901            * @name $location#port
11902            *
11903            * @description
11904            * This method is getter only.
11905            *
11906            * Return port of current url.
11907            *
11908            *
11909            * ```js
11910            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11911            * var port = $location.port();
11912            * // => 80
11913            * ```
11914            *
11915            * @return {Number} port
11916            */
11917           port: locationGetter('$$port'),
11918
11919           /**
11920            * @ngdoc method
11921            * @name $location#path
11922            *
11923            * @description
11924            * This method is getter / setter.
11925            *
11926            * Return path of current url when called without any parameter.
11927            *
11928            * Change path when called with parameter and return `$location`.
11929            *
11930            * Note: Path should always begin with forward slash (/), this method will add the forward slash
11931            * if it is missing.
11932            *
11933            *
11934            * ```js
11935            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11936            * var path = $location.path();
11937            * // => "/some/path"
11938            * ```
11939            *
11940            * @param {(string|number)=} path New path
11941            * @return {string} path
11942            */
11943           path: locationGetterSetter('$$path', function(path) {
11944             path = path !== null ? path.toString() : '';
11945             return path.charAt(0) == '/' ? path : '/' + path;
11946           }),
11947
11948           /**
11949            * @ngdoc method
11950            * @name $location#search
11951            *
11952            * @description
11953            * This method is getter / setter.
11954            *
11955            * Return search part (as object) of current url when called without any parameter.
11956            *
11957            * Change search part when called with parameter and return `$location`.
11958            *
11959            *
11960            * ```js
11961            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11962            * var searchObject = $location.search();
11963            * // => {foo: 'bar', baz: 'xoxo'}
11964            *
11965            * // set foo to 'yipee'
11966            * $location.search('foo', 'yipee');
11967            * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
11968            * ```
11969            *
11970            * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
11971            * hash object.
11972            *
11973            * When called with a single argument the method acts as a setter, setting the `search` component
11974            * of `$location` to the specified value.
11975            *
11976            * If the argument is a hash object containing an array of values, these values will be encoded
11977            * as duplicate search parameters in the url.
11978            *
11979            * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
11980            * will override only a single search property.
11981            *
11982            * If `paramValue` is an array, it will override the property of the `search` component of
11983            * `$location` specified via the first argument.
11984            *
11985            * If `paramValue` is `null`, the property specified via the first argument will be deleted.
11986            *
11987            * If `paramValue` is `true`, the property specified via the first argument will be added with no
11988            * value nor trailing equal sign.
11989            *
11990            * @return {Object} If called with no arguments returns the parsed `search` object. If called with
11991            * one or more arguments returns `$location` object itself.
11992            */
11993           search: function(search, paramValue) {
11994             switch (arguments.length) {
11995               case 0:
11996                 return this.$$search;
11997               case 1:
11998                 if (isString(search) || isNumber(search)) {
11999                   search = search.toString();
12000                   this.$$search = parseKeyValue(search);
12001                 } else if (isObject(search)) {
12002                   search = copy(search, {});
12003                   // remove object undefined or null properties
12004                   forEach(search, function(value, key) {
12005                     if (value == null) delete search[key];
12006                   });
12007
12008                   this.$$search = search;
12009                 } else {
12010                   throw $locationMinErr('isrcharg',
12011                       'The first argument of the `$location#search()` call must be a string or an object.');
12012                 }
12013                 break;
12014               default:
12015                 if (isUndefined(paramValue) || paramValue === null) {
12016                   delete this.$$search[search];
12017                 } else {
12018                   this.$$search[search] = paramValue;
12019                 }
12020             }
12021
12022             this.$$compose();
12023             return this;
12024           },
12025
12026           /**
12027            * @ngdoc method
12028            * @name $location#hash
12029            *
12030            * @description
12031            * This method is getter / setter.
12032            *
12033            * Returns the hash fragment when called without any parameters.
12034            *
12035            * Changes the hash fragment when called with a parameter and returns `$location`.
12036            *
12037            *
12038            * ```js
12039            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
12040            * var hash = $location.hash();
12041            * // => "hashValue"
12042            * ```
12043            *
12044            * @param {(string|number)=} hash New hash fragment
12045            * @return {string} hash
12046            */
12047           hash: locationGetterSetter('$$hash', function(hash) {
12048             return hash !== null ? hash.toString() : '';
12049           }),
12050
12051           /**
12052            * @ngdoc method
12053            * @name $location#replace
12054            *
12055            * @description
12056            * If called, all changes to $location during the current `$digest` will replace the current history
12057            * record, instead of adding a new one.
12058            */
12059           replace: function() {
12060             this.$$replace = true;
12061             return this;
12062           }
12063         };
12064
12065         forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
12066           Location.prototype = Object.create(locationPrototype);
12067
12068           /**
12069            * @ngdoc method
12070            * @name $location#state
12071            *
12072            * @description
12073            * This method is getter / setter.
12074            *
12075            * Return the history state object when called without any parameter.
12076            *
12077            * Change the history state object when called with one parameter and return `$location`.
12078            * The state object is later passed to `pushState` or `replaceState`.
12079            *
12080            * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
12081            * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
12082            * older browsers (like IE9 or Android < 4.0), don't use this method.
12083            *
12084            * @param {object=} state State object for pushState or replaceState
12085            * @return {object} state
12086            */
12087           Location.prototype.state = function(state) {
12088             if (!arguments.length) {
12089               return this.$$state;
12090             }
12091
12092             if (Location !== LocationHtml5Url || !this.$$html5) {
12093               throw $locationMinErr('nostate', 'History API state support is available only ' +
12094                 'in HTML5 mode and only in browsers supporting HTML5 History API');
12095             }
12096             // The user might modify `stateObject` after invoking `$location.state(stateObject)`
12097             // but we're changing the $$state reference to $browser.state() during the $digest
12098             // so the modification window is narrow.
12099             this.$$state = isUndefined(state) ? null : state;
12100
12101             return this;
12102           };
12103         });
12104
12105
12106         function locationGetter(property) {
12107           return function() {
12108             return this[property];
12109           };
12110         }
12111
12112
12113         function locationGetterSetter(property, preprocess) {
12114           return function(value) {
12115             if (isUndefined(value)) {
12116               return this[property];
12117             }
12118
12119             this[property] = preprocess(value);
12120             this.$$compose();
12121
12122             return this;
12123           };
12124         }
12125
12126
12127         /**
12128          * @ngdoc service
12129          * @name $location
12130          *
12131          * @requires $rootElement
12132          *
12133          * @description
12134          * The $location service parses the URL in the browser address bar (based on the
12135          * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
12136          * available to your application. Changes to the URL in the address bar are reflected into
12137          * $location service and changes to $location are reflected into the browser address bar.
12138          *
12139          * **The $location service:**
12140          *
12141          * - Exposes the current URL in the browser address bar, so you can
12142          *   - Watch and observe the URL.
12143          *   - Change the URL.
12144          * - Synchronizes the URL with the browser when the user
12145          *   - Changes the address bar.
12146          *   - Clicks the back or forward button (or clicks a History link).
12147          *   - Clicks on a link.
12148          * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
12149          *
12150          * For more information see {@link guide/$location Developer Guide: Using $location}
12151          */
12152
12153         /**
12154          * @ngdoc provider
12155          * @name $locationProvider
12156          * @description
12157          * Use the `$locationProvider` to configure how the application deep linking paths are stored.
12158          */
12159         function $LocationProvider() {
12160           var hashPrefix = '',
12161               html5Mode = {
12162                 enabled: false,
12163                 requireBase: true,
12164                 rewriteLinks: true
12165               };
12166
12167           /**
12168            * @ngdoc method
12169            * @name $locationProvider#hashPrefix
12170            * @description
12171            * @param {string=} prefix Prefix for hash part (containing path and search)
12172            * @returns {*} current value if used as getter or itself (chaining) if used as setter
12173            */
12174           this.hashPrefix = function(prefix) {
12175             if (isDefined(prefix)) {
12176               hashPrefix = prefix;
12177               return this;
12178             } else {
12179               return hashPrefix;
12180             }
12181           };
12182
12183           /**
12184            * @ngdoc method
12185            * @name $locationProvider#html5Mode
12186            * @description
12187            * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
12188            *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
12189            *   properties:
12190            *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
12191            *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
12192            *     support `pushState`.
12193            *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
12194            *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
12195            *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
12196            *     See the {@link guide/$location $location guide for more information}
12197            *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
12198            *     enables/disables url rewriting for relative links.
12199            *
12200            * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
12201            */
12202           this.html5Mode = function(mode) {
12203             if (isBoolean(mode)) {
12204               html5Mode.enabled = mode;
12205               return this;
12206             } else if (isObject(mode)) {
12207
12208               if (isBoolean(mode.enabled)) {
12209                 html5Mode.enabled = mode.enabled;
12210               }
12211
12212               if (isBoolean(mode.requireBase)) {
12213                 html5Mode.requireBase = mode.requireBase;
12214               }
12215
12216               if (isBoolean(mode.rewriteLinks)) {
12217                 html5Mode.rewriteLinks = mode.rewriteLinks;
12218               }
12219
12220               return this;
12221             } else {
12222               return html5Mode;
12223             }
12224           };
12225
12226           /**
12227            * @ngdoc event
12228            * @name $location#$locationChangeStart
12229            * @eventType broadcast on root scope
12230            * @description
12231            * Broadcasted before a URL will change.
12232            *
12233            * This change can be prevented by calling
12234            * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
12235            * details about event object. Upon successful change
12236            * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
12237            *
12238            * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
12239            * the browser supports the HTML5 History API.
12240            *
12241            * @param {Object} angularEvent Synthetic event object.
12242            * @param {string} newUrl New URL
12243            * @param {string=} oldUrl URL that was before it was changed.
12244            * @param {string=} newState New history state object
12245            * @param {string=} oldState History state object that was before it was changed.
12246            */
12247
12248           /**
12249            * @ngdoc event
12250            * @name $location#$locationChangeSuccess
12251            * @eventType broadcast on root scope
12252            * @description
12253            * Broadcasted after a URL was changed.
12254            *
12255            * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
12256            * the browser supports the HTML5 History API.
12257            *
12258            * @param {Object} angularEvent Synthetic event object.
12259            * @param {string} newUrl New URL
12260            * @param {string=} oldUrl URL that was before it was changed.
12261            * @param {string=} newState New history state object
12262            * @param {string=} oldState History state object that was before it was changed.
12263            */
12264
12265           this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
12266               function($rootScope, $browser, $sniffer, $rootElement, $window) {
12267             var $location,
12268                 LocationMode,
12269                 baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
12270                 initialUrl = $browser.url(),
12271                 appBase;
12272
12273             if (html5Mode.enabled) {
12274               if (!baseHref && html5Mode.requireBase) {
12275                 throw $locationMinErr('nobase',
12276                   "$location in HTML5 mode requires a <base> tag to be present!");
12277               }
12278               appBase = serverBase(initialUrl) + (baseHref || '/');
12279               LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
12280             } else {
12281               appBase = stripHash(initialUrl);
12282               LocationMode = LocationHashbangUrl;
12283             }
12284             var appBaseNoFile = stripFile(appBase);
12285
12286             $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
12287             $location.$$parseLinkUrl(initialUrl, initialUrl);
12288
12289             $location.$$state = $browser.state();
12290
12291             var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
12292
12293             function setBrowserUrlWithFallback(url, replace, state) {
12294               var oldUrl = $location.url();
12295               var oldState = $location.$$state;
12296               try {
12297                 $browser.url(url, replace, state);
12298
12299                 // Make sure $location.state() returns referentially identical (not just deeply equal)
12300                 // state object; this makes possible quick checking if the state changed in the digest
12301                 // loop. Checking deep equality would be too expensive.
12302                 $location.$$state = $browser.state();
12303               } catch (e) {
12304                 // Restore old values if pushState fails
12305                 $location.url(oldUrl);
12306                 $location.$$state = oldState;
12307
12308                 throw e;
12309               }
12310             }
12311
12312             $rootElement.on('click', function(event) {
12313               // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
12314               // currently we open nice url link and redirect then
12315
12316               if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
12317
12318               var elm = jqLite(event.target);
12319
12320               // traverse the DOM up to find first A tag
12321               while (nodeName_(elm[0]) !== 'a') {
12322                 // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
12323                 if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
12324               }
12325
12326               var absHref = elm.prop('href');
12327               // get the actual href attribute - see
12328               // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
12329               var relHref = elm.attr('href') || elm.attr('xlink:href');
12330
12331               if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
12332                 // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
12333                 // an animation.
12334                 absHref = urlResolve(absHref.animVal).href;
12335               }
12336
12337               // Ignore when url is started with javascript: or mailto:
12338               if (IGNORE_URI_REGEXP.test(absHref)) return;
12339
12340               if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
12341                 if ($location.$$parseLinkUrl(absHref, relHref)) {
12342                   // We do a preventDefault for all urls that are part of the angular application,
12343                   // in html5mode and also without, so that we are able to abort navigation without
12344                   // getting double entries in the location history.
12345                   event.preventDefault();
12346                   // update location manually
12347                   if ($location.absUrl() != $browser.url()) {
12348                     $rootScope.$apply();
12349                     // hack to work around FF6 bug 684208 when scenario runner clicks on links
12350                     $window.angular['ff-684208-preventDefault'] = true;
12351                   }
12352                 }
12353               }
12354             });
12355
12356
12357             // rewrite hashbang url <> html5 url
12358             if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
12359               $browser.url($location.absUrl(), true);
12360             }
12361
12362             var initializing = true;
12363
12364             // update $location when $browser url changes
12365             $browser.onUrlChange(function(newUrl, newState) {
12366
12367               if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
12368                 // If we are navigating outside of the app then force a reload
12369                 $window.location.href = newUrl;
12370                 return;
12371               }
12372
12373               $rootScope.$evalAsync(function() {
12374                 var oldUrl = $location.absUrl();
12375                 var oldState = $location.$$state;
12376                 var defaultPrevented;
12377                 newUrl = trimEmptyHash(newUrl);
12378                 $location.$$parse(newUrl);
12379                 $location.$$state = newState;
12380
12381                 defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12382                     newState, oldState).defaultPrevented;
12383
12384                 // if the location was changed by a `$locationChangeStart` handler then stop
12385                 // processing this location change
12386                 if ($location.absUrl() !== newUrl) return;
12387
12388                 if (defaultPrevented) {
12389                   $location.$$parse(oldUrl);
12390                   $location.$$state = oldState;
12391                   setBrowserUrlWithFallback(oldUrl, false, oldState);
12392                 } else {
12393                   initializing = false;
12394                   afterLocationChange(oldUrl, oldState);
12395                 }
12396               });
12397               if (!$rootScope.$$phase) $rootScope.$digest();
12398             });
12399
12400             // update browser
12401             $rootScope.$watch(function $locationWatch() {
12402               var oldUrl = trimEmptyHash($browser.url());
12403               var newUrl = trimEmptyHash($location.absUrl());
12404               var oldState = $browser.state();
12405               var currentReplace = $location.$$replace;
12406               var urlOrStateChanged = oldUrl !== newUrl ||
12407                 ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
12408
12409               if (initializing || urlOrStateChanged) {
12410                 initializing = false;
12411
12412                 $rootScope.$evalAsync(function() {
12413                   var newUrl = $location.absUrl();
12414                   var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12415                       $location.$$state, oldState).defaultPrevented;
12416
12417                   // if the location was changed by a `$locationChangeStart` handler then stop
12418                   // processing this location change
12419                   if ($location.absUrl() !== newUrl) return;
12420
12421                   if (defaultPrevented) {
12422                     $location.$$parse(oldUrl);
12423                     $location.$$state = oldState;
12424                   } else {
12425                     if (urlOrStateChanged) {
12426                       setBrowserUrlWithFallback(newUrl, currentReplace,
12427                                                 oldState === $location.$$state ? null : $location.$$state);
12428                     }
12429                     afterLocationChange(oldUrl, oldState);
12430                   }
12431                 });
12432               }
12433
12434               $location.$$replace = false;
12435
12436               // we don't need to return anything because $evalAsync will make the digest loop dirty when
12437               // there is a change
12438             });
12439
12440             return $location;
12441
12442             function afterLocationChange(oldUrl, oldState) {
12443               $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
12444                 $location.$$state, oldState);
12445             }
12446         }];
12447         }
12448
12449         /**
12450          * @ngdoc service
12451          * @name $log
12452          * @requires $window
12453          *
12454          * @description
12455          * Simple service for logging. Default implementation safely writes the message
12456          * into the browser's console (if present).
12457          *
12458          * The main purpose of this service is to simplify debugging and troubleshooting.
12459          *
12460          * The default is to log `debug` messages. You can use
12461          * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
12462          *
12463          * @example
12464            <example module="logExample">
12465              <file name="script.js">
12466                angular.module('logExample', [])
12467                  .controller('LogController', ['$scope', '$log', function($scope, $log) {
12468                    $scope.$log = $log;
12469                    $scope.message = 'Hello World!';
12470                  }]);
12471              </file>
12472              <file name="index.html">
12473                <div ng-controller="LogController">
12474                  <p>Reload this page with open console, enter text and hit the log button...</p>
12475                  <label>Message:
12476                  <input type="text" ng-model="message" /></label>
12477                  <button ng-click="$log.log(message)">log</button>
12478                  <button ng-click="$log.warn(message)">warn</button>
12479                  <button ng-click="$log.info(message)">info</button>
12480                  <button ng-click="$log.error(message)">error</button>
12481                  <button ng-click="$log.debug(message)">debug</button>
12482                </div>
12483              </file>
12484            </example>
12485          */
12486
12487         /**
12488          * @ngdoc provider
12489          * @name $logProvider
12490          * @description
12491          * Use the `$logProvider` to configure how the application logs messages
12492          */
12493         function $LogProvider() {
12494           var debug = true,
12495               self = this;
12496
12497           /**
12498            * @ngdoc method
12499            * @name $logProvider#debugEnabled
12500            * @description
12501            * @param {boolean=} flag enable or disable debug level messages
12502            * @returns {*} current value if used as getter or itself (chaining) if used as setter
12503            */
12504           this.debugEnabled = function(flag) {
12505             if (isDefined(flag)) {
12506               debug = flag;
12507             return this;
12508             } else {
12509               return debug;
12510             }
12511           };
12512
12513           this.$get = ['$window', function($window) {
12514             return {
12515               /**
12516                * @ngdoc method
12517                * @name $log#log
12518                *
12519                * @description
12520                * Write a log message
12521                */
12522               log: consoleLog('log'),
12523
12524               /**
12525                * @ngdoc method
12526                * @name $log#info
12527                *
12528                * @description
12529                * Write an information message
12530                */
12531               info: consoleLog('info'),
12532
12533               /**
12534                * @ngdoc method
12535                * @name $log#warn
12536                *
12537                * @description
12538                * Write a warning message
12539                */
12540               warn: consoleLog('warn'),
12541
12542               /**
12543                * @ngdoc method
12544                * @name $log#error
12545                *
12546                * @description
12547                * Write an error message
12548                */
12549               error: consoleLog('error'),
12550
12551               /**
12552                * @ngdoc method
12553                * @name $log#debug
12554                *
12555                * @description
12556                * Write a debug message
12557                */
12558               debug: (function() {
12559                 var fn = consoleLog('debug');
12560
12561                 return function() {
12562                   if (debug) {
12563                     fn.apply(self, arguments);
12564                   }
12565                 };
12566               }())
12567             };
12568
12569             function formatError(arg) {
12570               if (arg instanceof Error) {
12571                 if (arg.stack) {
12572                   arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
12573                       ? 'Error: ' + arg.message + '\n' + arg.stack
12574                       : arg.stack;
12575                 } else if (arg.sourceURL) {
12576                   arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
12577                 }
12578               }
12579               return arg;
12580             }
12581
12582             function consoleLog(type) {
12583               var console = $window.console || {},
12584                   logFn = console[type] || console.log || noop,
12585                   hasApply = false;
12586
12587               // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
12588               // The reason behind this is that console.log has type "object" in IE8...
12589               try {
12590                 hasApply = !!logFn.apply;
12591               } catch (e) {}
12592
12593               if (hasApply) {
12594                 return function() {
12595                   var args = [];
12596                   forEach(arguments, function(arg) {
12597                     args.push(formatError(arg));
12598                   });
12599                   return logFn.apply(console, args);
12600                 };
12601               }
12602
12603               // we are IE which either doesn't have window.console => this is noop and we do nothing,
12604               // or we are IE where console.log doesn't have apply so we log at least first 2 args
12605               return function(arg1, arg2) {
12606                 logFn(arg1, arg2 == null ? '' : arg2);
12607               };
12608             }
12609           }];
12610         }
12611
12612         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
12613          *     Any commits to this file should be reviewed with security in mind.  *
12614          *   Changes to this file can potentially create security vulnerabilities. *
12615          *          An approval from 2 Core members with history of modifying      *
12616          *                         this file is required.                          *
12617          *                                                                         *
12618          *  Does the change somehow allow for arbitrary javascript to be executed? *
12619          *    Or allows for someone to change the prototype of built-in objects?   *
12620          *     Or gives undesired access to variables likes document or window?    *
12621          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12622
12623         var $parseMinErr = minErr('$parse');
12624
12625         // Sandboxing Angular Expressions
12626         // ------------------------------
12627         // Angular expressions are generally considered safe because these expressions only have direct
12628         // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
12629         // obtaining a reference to native JS functions such as the Function constructor.
12630         //
12631         // As an example, consider the following Angular expression:
12632         //
12633         //   {}.toString.constructor('alert("evil JS code")')
12634         //
12635         // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
12636         // against the expression language, but not to prevent exploits that were enabled by exposing
12637         // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
12638         // practice and therefore we are not even trying to protect against interaction with an object
12639         // explicitly exposed in this way.
12640         //
12641         // In general, it is not possible to access a Window object from an angular expression unless a
12642         // window or some DOM object that has a reference to window is published onto a Scope.
12643         // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
12644         // native objects.
12645         //
12646         // See https://docs.angularjs.org/guide/security
12647
12648
12649         function ensureSafeMemberName(name, fullExpression) {
12650           if (name === "__defineGetter__" || name === "__defineSetter__"
12651               || name === "__lookupGetter__" || name === "__lookupSetter__"
12652               || name === "__proto__") {
12653             throw $parseMinErr('isecfld',
12654                 'Attempting to access a disallowed field in Angular expressions! '
12655                 + 'Expression: {0}', fullExpression);
12656           }
12657           return name;
12658         }
12659
12660         function getStringValue(name, fullExpression) {
12661           // From the JavaScript docs:
12662           // Property names must be strings. This means that non-string objects cannot be used
12663           // as keys in an object. Any non-string object, including a number, is typecasted
12664           // into a string via the toString method.
12665           //
12666           // So, to ensure that we are checking the same `name` that JavaScript would use,
12667           // we cast it to a string, if possible.
12668           // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
12669           // this is, this will handle objects that misbehave.
12670           name = name + '';
12671           if (!isString(name)) {
12672             throw $parseMinErr('iseccst',
12673                 'Cannot convert object to primitive value! '
12674                 + 'Expression: {0}', fullExpression);
12675           }
12676           return name;
12677         }
12678
12679         function ensureSafeObject(obj, fullExpression) {
12680           // nifty check if obj is Function that is fast and works across iframes and other contexts
12681           if (obj) {
12682             if (obj.constructor === obj) {
12683               throw $parseMinErr('isecfn',
12684                   'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12685                   fullExpression);
12686             } else if (// isWindow(obj)
12687                 obj.window === obj) {
12688               throw $parseMinErr('isecwindow',
12689                   'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
12690                   fullExpression);
12691             } else if (// isElement(obj)
12692                 obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
12693               throw $parseMinErr('isecdom',
12694                   'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
12695                   fullExpression);
12696             } else if (// block Object so that we can't get hold of dangerous Object.* methods
12697                 obj === Object) {
12698               throw $parseMinErr('isecobj',
12699                   'Referencing Object in Angular expressions is disallowed! Expression: {0}',
12700                   fullExpression);
12701             }
12702           }
12703           return obj;
12704         }
12705
12706         var CALL = Function.prototype.call;
12707         var APPLY = Function.prototype.apply;
12708         var BIND = Function.prototype.bind;
12709
12710         function ensureSafeFunction(obj, fullExpression) {
12711           if (obj) {
12712             if (obj.constructor === obj) {
12713               throw $parseMinErr('isecfn',
12714                 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12715                 fullExpression);
12716             } else if (obj === CALL || obj === APPLY || obj === BIND) {
12717               throw $parseMinErr('isecff',
12718                 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
12719                 fullExpression);
12720             }
12721           }
12722         }
12723
12724         function ensureSafeAssignContext(obj, fullExpression) {
12725           if (obj) {
12726             if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
12727                 obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
12728               throw $parseMinErr('isecaf',
12729                 'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
12730             }
12731           }
12732         }
12733
12734         var OPERATORS = createMap();
12735         forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
12736         var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
12737
12738
12739         /////////////////////////////////////////
12740
12741
12742         /**
12743          * @constructor
12744          */
12745         var Lexer = function(options) {
12746           this.options = options;
12747         };
12748
12749         Lexer.prototype = {
12750           constructor: Lexer,
12751
12752           lex: function(text) {
12753             this.text = text;
12754             this.index = 0;
12755             this.tokens = [];
12756
12757             while (this.index < this.text.length) {
12758               var ch = this.text.charAt(this.index);
12759               if (ch === '"' || ch === "'") {
12760                 this.readString(ch);
12761               } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
12762                 this.readNumber();
12763               } else if (this.isIdent(ch)) {
12764                 this.readIdent();
12765               } else if (this.is(ch, '(){}[].,;:?')) {
12766                 this.tokens.push({index: this.index, text: ch});
12767                 this.index++;
12768               } else if (this.isWhitespace(ch)) {
12769                 this.index++;
12770               } else {
12771                 var ch2 = ch + this.peek();
12772                 var ch3 = ch2 + this.peek(2);
12773                 var op1 = OPERATORS[ch];
12774                 var op2 = OPERATORS[ch2];
12775                 var op3 = OPERATORS[ch3];
12776                 if (op1 || op2 || op3) {
12777                   var token = op3 ? ch3 : (op2 ? ch2 : ch);
12778                   this.tokens.push({index: this.index, text: token, operator: true});
12779                   this.index += token.length;
12780                 } else {
12781                   this.throwError('Unexpected next character ', this.index, this.index + 1);
12782                 }
12783               }
12784             }
12785             return this.tokens;
12786           },
12787
12788           is: function(ch, chars) {
12789             return chars.indexOf(ch) !== -1;
12790           },
12791
12792           peek: function(i) {
12793             var num = i || 1;
12794             return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
12795           },
12796
12797           isNumber: function(ch) {
12798             return ('0' <= ch && ch <= '9') && typeof ch === "string";
12799           },
12800
12801           isWhitespace: function(ch) {
12802             // IE treats non-breaking space as \u00A0
12803             return (ch === ' ' || ch === '\r' || ch === '\t' ||
12804                     ch === '\n' || ch === '\v' || ch === '\u00A0');
12805           },
12806
12807           isIdent: function(ch) {
12808             return ('a' <= ch && ch <= 'z' ||
12809                     'A' <= ch && ch <= 'Z' ||
12810                     '_' === ch || ch === '$');
12811           },
12812
12813           isExpOperator: function(ch) {
12814             return (ch === '-' || ch === '+' || this.isNumber(ch));
12815           },
12816
12817           throwError: function(error, start, end) {
12818             end = end || this.index;
12819             var colStr = (isDefined(start)
12820                     ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
12821                     : ' ' + end);
12822             throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
12823                 error, colStr, this.text);
12824           },
12825
12826           readNumber: function() {
12827             var number = '';
12828             var start = this.index;
12829             while (this.index < this.text.length) {
12830               var ch = lowercase(this.text.charAt(this.index));
12831               if (ch == '.' || this.isNumber(ch)) {
12832                 number += ch;
12833               } else {
12834                 var peekCh = this.peek();
12835                 if (ch == 'e' && this.isExpOperator(peekCh)) {
12836                   number += ch;
12837                 } else if (this.isExpOperator(ch) &&
12838                     peekCh && this.isNumber(peekCh) &&
12839                     number.charAt(number.length - 1) == 'e') {
12840                   number += ch;
12841                 } else if (this.isExpOperator(ch) &&
12842                     (!peekCh || !this.isNumber(peekCh)) &&
12843                     number.charAt(number.length - 1) == 'e') {
12844                   this.throwError('Invalid exponent');
12845                 } else {
12846                   break;
12847                 }
12848               }
12849               this.index++;
12850             }
12851             this.tokens.push({
12852               index: start,
12853               text: number,
12854               constant: true,
12855               value: Number(number)
12856             });
12857           },
12858
12859           readIdent: function() {
12860             var start = this.index;
12861             while (this.index < this.text.length) {
12862               var ch = this.text.charAt(this.index);
12863               if (!(this.isIdent(ch) || this.isNumber(ch))) {
12864                 break;
12865               }
12866               this.index++;
12867             }
12868             this.tokens.push({
12869               index: start,
12870               text: this.text.slice(start, this.index),
12871               identifier: true
12872             });
12873           },
12874
12875           readString: function(quote) {
12876             var start = this.index;
12877             this.index++;
12878             var string = '';
12879             var rawString = quote;
12880             var escape = false;
12881             while (this.index < this.text.length) {
12882               var ch = this.text.charAt(this.index);
12883               rawString += ch;
12884               if (escape) {
12885                 if (ch === 'u') {
12886                   var hex = this.text.substring(this.index + 1, this.index + 5);
12887                   if (!hex.match(/[\da-f]{4}/i)) {
12888                     this.throwError('Invalid unicode escape [\\u' + hex + ']');
12889                   }
12890                   this.index += 4;
12891                   string += String.fromCharCode(parseInt(hex, 16));
12892                 } else {
12893                   var rep = ESCAPE[ch];
12894                   string = string + (rep || ch);
12895                 }
12896                 escape = false;
12897               } else if (ch === '\\') {
12898                 escape = true;
12899               } else if (ch === quote) {
12900                 this.index++;
12901                 this.tokens.push({
12902                   index: start,
12903                   text: rawString,
12904                   constant: true,
12905                   value: string
12906                 });
12907                 return;
12908               } else {
12909                 string += ch;
12910               }
12911               this.index++;
12912             }
12913             this.throwError('Unterminated quote', start);
12914           }
12915         };
12916
12917         var AST = function(lexer, options) {
12918           this.lexer = lexer;
12919           this.options = options;
12920         };
12921
12922         AST.Program = 'Program';
12923         AST.ExpressionStatement = 'ExpressionStatement';
12924         AST.AssignmentExpression = 'AssignmentExpression';
12925         AST.ConditionalExpression = 'ConditionalExpression';
12926         AST.LogicalExpression = 'LogicalExpression';
12927         AST.BinaryExpression = 'BinaryExpression';
12928         AST.UnaryExpression = 'UnaryExpression';
12929         AST.CallExpression = 'CallExpression';
12930         AST.MemberExpression = 'MemberExpression';
12931         AST.Identifier = 'Identifier';
12932         AST.Literal = 'Literal';
12933         AST.ArrayExpression = 'ArrayExpression';
12934         AST.Property = 'Property';
12935         AST.ObjectExpression = 'ObjectExpression';
12936         AST.ThisExpression = 'ThisExpression';
12937
12938         // Internal use only
12939         AST.NGValueParameter = 'NGValueParameter';
12940
12941         AST.prototype = {
12942           ast: function(text) {
12943             this.text = text;
12944             this.tokens = this.lexer.lex(text);
12945
12946             var value = this.program();
12947
12948             if (this.tokens.length !== 0) {
12949               this.throwError('is an unexpected token', this.tokens[0]);
12950             }
12951
12952             return value;
12953           },
12954
12955           program: function() {
12956             var body = [];
12957             while (true) {
12958               if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
12959                 body.push(this.expressionStatement());
12960               if (!this.expect(';')) {
12961                 return { type: AST.Program, body: body};
12962               }
12963             }
12964           },
12965
12966           expressionStatement: function() {
12967             return { type: AST.ExpressionStatement, expression: this.filterChain() };
12968           },
12969
12970           filterChain: function() {
12971             var left = this.expression();
12972             var token;
12973             while ((token = this.expect('|'))) {
12974               left = this.filter(left);
12975             }
12976             return left;
12977           },
12978
12979           expression: function() {
12980             return this.assignment();
12981           },
12982
12983           assignment: function() {
12984             var result = this.ternary();
12985             if (this.expect('=')) {
12986               result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
12987             }
12988             return result;
12989           },
12990
12991           ternary: function() {
12992             var test = this.logicalOR();
12993             var alternate;
12994             var consequent;
12995             if (this.expect('?')) {
12996               alternate = this.expression();
12997               if (this.consume(':')) {
12998                 consequent = this.expression();
12999                 return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
13000               }
13001             }
13002             return test;
13003           },
13004
13005           logicalOR: function() {
13006             var left = this.logicalAND();
13007             while (this.expect('||')) {
13008               left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
13009             }
13010             return left;
13011           },
13012
13013           logicalAND: function() {
13014             var left = this.equality();
13015             while (this.expect('&&')) {
13016               left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
13017             }
13018             return left;
13019           },
13020
13021           equality: function() {
13022             var left = this.relational();
13023             var token;
13024             while ((token = this.expect('==','!=','===','!=='))) {
13025               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
13026             }
13027             return left;
13028           },
13029
13030           relational: function() {
13031             var left = this.additive();
13032             var token;
13033             while ((token = this.expect('<', '>', '<=', '>='))) {
13034               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
13035             }
13036             return left;
13037           },
13038
13039           additive: function() {
13040             var left = this.multiplicative();
13041             var token;
13042             while ((token = this.expect('+','-'))) {
13043               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
13044             }
13045             return left;
13046           },
13047
13048           multiplicative: function() {
13049             var left = this.unary();
13050             var token;
13051             while ((token = this.expect('*','/','%'))) {
13052               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
13053             }
13054             return left;
13055           },
13056
13057           unary: function() {
13058             var token;
13059             if ((token = this.expect('+', '-', '!'))) {
13060               return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
13061             } else {
13062               return this.primary();
13063             }
13064           },
13065
13066           primary: function() {
13067             var primary;
13068             if (this.expect('(')) {
13069               primary = this.filterChain();
13070               this.consume(')');
13071             } else if (this.expect('[')) {
13072               primary = this.arrayDeclaration();
13073             } else if (this.expect('{')) {
13074               primary = this.object();
13075             } else if (this.constants.hasOwnProperty(this.peek().text)) {
13076               primary = copy(this.constants[this.consume().text]);
13077             } else if (this.peek().identifier) {
13078               primary = this.identifier();
13079             } else if (this.peek().constant) {
13080               primary = this.constant();
13081             } else {
13082               this.throwError('not a primary expression', this.peek());
13083             }
13084
13085             var next;
13086             while ((next = this.expect('(', '[', '.'))) {
13087               if (next.text === '(') {
13088                 primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
13089                 this.consume(')');
13090               } else if (next.text === '[') {
13091                 primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
13092                 this.consume(']');
13093               } else if (next.text === '.') {
13094                 primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
13095               } else {
13096                 this.throwError('IMPOSSIBLE');
13097               }
13098             }
13099             return primary;
13100           },
13101
13102           filter: function(baseExpression) {
13103             var args = [baseExpression];
13104             var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
13105
13106             while (this.expect(':')) {
13107               args.push(this.expression());
13108             }
13109
13110             return result;
13111           },
13112
13113           parseArguments: function() {
13114             var args = [];
13115             if (this.peekToken().text !== ')') {
13116               do {
13117                 args.push(this.expression());
13118               } while (this.expect(','));
13119             }
13120             return args;
13121           },
13122
13123           identifier: function() {
13124             var token = this.consume();
13125             if (!token.identifier) {
13126               this.throwError('is not a valid identifier', token);
13127             }
13128             return { type: AST.Identifier, name: token.text };
13129           },
13130
13131           constant: function() {
13132             // TODO check that it is a constant
13133             return { type: AST.Literal, value: this.consume().value };
13134           },
13135
13136           arrayDeclaration: function() {
13137             var elements = [];
13138             if (this.peekToken().text !== ']') {
13139               do {
13140                 if (this.peek(']')) {
13141                   // Support trailing commas per ES5.1.
13142                   break;
13143                 }
13144                 elements.push(this.expression());
13145               } while (this.expect(','));
13146             }
13147             this.consume(']');
13148
13149             return { type: AST.ArrayExpression, elements: elements };
13150           },
13151
13152           object: function() {
13153             var properties = [], property;
13154             if (this.peekToken().text !== '}') {
13155               do {
13156                 if (this.peek('}')) {
13157                   // Support trailing commas per ES5.1.
13158                   break;
13159                 }
13160                 property = {type: AST.Property, kind: 'init'};
13161                 if (this.peek().constant) {
13162                   property.key = this.constant();
13163                 } else if (this.peek().identifier) {
13164                   property.key = this.identifier();
13165                 } else {
13166                   this.throwError("invalid key", this.peek());
13167                 }
13168                 this.consume(':');
13169                 property.value = this.expression();
13170                 properties.push(property);
13171               } while (this.expect(','));
13172             }
13173             this.consume('}');
13174
13175             return {type: AST.ObjectExpression, properties: properties };
13176           },
13177
13178           throwError: function(msg, token) {
13179             throw $parseMinErr('syntax',
13180                 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
13181                   token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
13182           },
13183
13184           consume: function(e1) {
13185             if (this.tokens.length === 0) {
13186               throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
13187             }
13188
13189             var token = this.expect(e1);
13190             if (!token) {
13191               this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
13192             }
13193             return token;
13194           },
13195
13196           peekToken: function() {
13197             if (this.tokens.length === 0) {
13198               throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
13199             }
13200             return this.tokens[0];
13201           },
13202
13203           peek: function(e1, e2, e3, e4) {
13204             return this.peekAhead(0, e1, e2, e3, e4);
13205           },
13206
13207           peekAhead: function(i, e1, e2, e3, e4) {
13208             if (this.tokens.length > i) {
13209               var token = this.tokens[i];
13210               var t = token.text;
13211               if (t === e1 || t === e2 || t === e3 || t === e4 ||
13212                   (!e1 && !e2 && !e3 && !e4)) {
13213                 return token;
13214               }
13215             }
13216             return false;
13217           },
13218
13219           expect: function(e1, e2, e3, e4) {
13220             var token = this.peek(e1, e2, e3, e4);
13221             if (token) {
13222               this.tokens.shift();
13223               return token;
13224             }
13225             return false;
13226           },
13227
13228
13229           /* `undefined` is not a constant, it is an identifier,
13230            * but using it as an identifier is not supported
13231            */
13232           constants: {
13233             'true': { type: AST.Literal, value: true },
13234             'false': { type: AST.Literal, value: false },
13235             'null': { type: AST.Literal, value: null },
13236             'undefined': {type: AST.Literal, value: undefined },
13237             'this': {type: AST.ThisExpression }
13238           }
13239         };
13240
13241         function ifDefined(v, d) {
13242           return typeof v !== 'undefined' ? v : d;
13243         }
13244
13245         function plusFn(l, r) {
13246           if (typeof l === 'undefined') return r;
13247           if (typeof r === 'undefined') return l;
13248           return l + r;
13249         }
13250
13251         function isStateless($filter, filterName) {
13252           var fn = $filter(filterName);
13253           return !fn.$stateful;
13254         }
13255
13256         function findConstantAndWatchExpressions(ast, $filter) {
13257           var allConstants;
13258           var argsToWatch;
13259           switch (ast.type) {
13260           case AST.Program:
13261             allConstants = true;
13262             forEach(ast.body, function(expr) {
13263               findConstantAndWatchExpressions(expr.expression, $filter);
13264               allConstants = allConstants && expr.expression.constant;
13265             });
13266             ast.constant = allConstants;
13267             break;
13268           case AST.Literal:
13269             ast.constant = true;
13270             ast.toWatch = [];
13271             break;
13272           case AST.UnaryExpression:
13273             findConstantAndWatchExpressions(ast.argument, $filter);
13274             ast.constant = ast.argument.constant;
13275             ast.toWatch = ast.argument.toWatch;
13276             break;
13277           case AST.BinaryExpression:
13278             findConstantAndWatchExpressions(ast.left, $filter);
13279             findConstantAndWatchExpressions(ast.right, $filter);
13280             ast.constant = ast.left.constant && ast.right.constant;
13281             ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
13282             break;
13283           case AST.LogicalExpression:
13284             findConstantAndWatchExpressions(ast.left, $filter);
13285             findConstantAndWatchExpressions(ast.right, $filter);
13286             ast.constant = ast.left.constant && ast.right.constant;
13287             ast.toWatch = ast.constant ? [] : [ast];
13288             break;
13289           case AST.ConditionalExpression:
13290             findConstantAndWatchExpressions(ast.test, $filter);
13291             findConstantAndWatchExpressions(ast.alternate, $filter);
13292             findConstantAndWatchExpressions(ast.consequent, $filter);
13293             ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
13294             ast.toWatch = ast.constant ? [] : [ast];
13295             break;
13296           case AST.Identifier:
13297             ast.constant = false;
13298             ast.toWatch = [ast];
13299             break;
13300           case AST.MemberExpression:
13301             findConstantAndWatchExpressions(ast.object, $filter);
13302             if (ast.computed) {
13303               findConstantAndWatchExpressions(ast.property, $filter);
13304             }
13305             ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
13306             ast.toWatch = [ast];
13307             break;
13308           case AST.CallExpression:
13309             allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
13310             argsToWatch = [];
13311             forEach(ast.arguments, function(expr) {
13312               findConstantAndWatchExpressions(expr, $filter);
13313               allConstants = allConstants && expr.constant;
13314               if (!expr.constant) {
13315                 argsToWatch.push.apply(argsToWatch, expr.toWatch);
13316               }
13317             });
13318             ast.constant = allConstants;
13319             ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
13320             break;
13321           case AST.AssignmentExpression:
13322             findConstantAndWatchExpressions(ast.left, $filter);
13323             findConstantAndWatchExpressions(ast.right, $filter);
13324             ast.constant = ast.left.constant && ast.right.constant;
13325             ast.toWatch = [ast];
13326             break;
13327           case AST.ArrayExpression:
13328             allConstants = true;
13329             argsToWatch = [];
13330             forEach(ast.elements, function(expr) {
13331               findConstantAndWatchExpressions(expr, $filter);
13332               allConstants = allConstants && expr.constant;
13333               if (!expr.constant) {
13334                 argsToWatch.push.apply(argsToWatch, expr.toWatch);
13335               }
13336             });
13337             ast.constant = allConstants;
13338             ast.toWatch = argsToWatch;
13339             break;
13340           case AST.ObjectExpression:
13341             allConstants = true;
13342             argsToWatch = [];
13343             forEach(ast.properties, function(property) {
13344               findConstantAndWatchExpressions(property.value, $filter);
13345               allConstants = allConstants && property.value.constant;
13346               if (!property.value.constant) {
13347                 argsToWatch.push.apply(argsToWatch, property.value.toWatch);
13348               }
13349             });
13350             ast.constant = allConstants;
13351             ast.toWatch = argsToWatch;
13352             break;
13353           case AST.ThisExpression:
13354             ast.constant = false;
13355             ast.toWatch = [];
13356             break;
13357           }
13358         }
13359
13360         function getInputs(body) {
13361           if (body.length != 1) return;
13362           var lastExpression = body[0].expression;
13363           var candidate = lastExpression.toWatch;
13364           if (candidate.length !== 1) return candidate;
13365           return candidate[0] !== lastExpression ? candidate : undefined;
13366         }
13367
13368         function isAssignable(ast) {
13369           return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
13370         }
13371
13372         function assignableAST(ast) {
13373           if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
13374             return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
13375           }
13376         }
13377
13378         function isLiteral(ast) {
13379           return ast.body.length === 0 ||
13380               ast.body.length === 1 && (
13381               ast.body[0].expression.type === AST.Literal ||
13382               ast.body[0].expression.type === AST.ArrayExpression ||
13383               ast.body[0].expression.type === AST.ObjectExpression);
13384         }
13385
13386         function isConstant(ast) {
13387           return ast.constant;
13388         }
13389
13390         function ASTCompiler(astBuilder, $filter) {
13391           this.astBuilder = astBuilder;
13392           this.$filter = $filter;
13393         }
13394
13395         ASTCompiler.prototype = {
13396           compile: function(expression, expensiveChecks) {
13397             var self = this;
13398             var ast = this.astBuilder.ast(expression);
13399             this.state = {
13400               nextId: 0,
13401               filters: {},
13402               expensiveChecks: expensiveChecks,
13403               fn: {vars: [], body: [], own: {}},
13404               assign: {vars: [], body: [], own: {}},
13405               inputs: []
13406             };
13407             findConstantAndWatchExpressions(ast, self.$filter);
13408             var extra = '';
13409             var assignable;
13410             this.stage = 'assign';
13411             if ((assignable = assignableAST(ast))) {
13412               this.state.computing = 'assign';
13413               var result = this.nextId();
13414               this.recurse(assignable, result);
13415               this.return_(result);
13416               extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
13417             }
13418             var toWatch = getInputs(ast.body);
13419             self.stage = 'inputs';
13420             forEach(toWatch, function(watch, key) {
13421               var fnKey = 'fn' + key;
13422               self.state[fnKey] = {vars: [], body: [], own: {}};
13423               self.state.computing = fnKey;
13424               var intoId = self.nextId();
13425               self.recurse(watch, intoId);
13426               self.return_(intoId);
13427               self.state.inputs.push(fnKey);
13428               watch.watchId = key;
13429             });
13430             this.state.computing = 'fn';
13431             this.stage = 'main';
13432             this.recurse(ast);
13433             var fnString =
13434               // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
13435               // This is a workaround for this until we do a better job at only removing the prefix only when we should.
13436               '"' + this.USE + ' ' + this.STRICT + '";\n' +
13437               this.filterPrefix() +
13438               'var fn=' + this.generateFunction('fn', 's,l,a,i') +
13439               extra +
13440               this.watchFns() +
13441               'return fn;';
13442
13443             /* jshint -W054 */
13444             var fn = (new Function('$filter',
13445                 'ensureSafeMemberName',
13446                 'ensureSafeObject',
13447                 'ensureSafeFunction',
13448                 'getStringValue',
13449                 'ensureSafeAssignContext',
13450                 'ifDefined',
13451                 'plus',
13452                 'text',
13453                 fnString))(
13454                   this.$filter,
13455                   ensureSafeMemberName,
13456                   ensureSafeObject,
13457                   ensureSafeFunction,
13458                   getStringValue,
13459                   ensureSafeAssignContext,
13460                   ifDefined,
13461                   plusFn,
13462                   expression);
13463             /* jshint +W054 */
13464             this.state = this.stage = undefined;
13465             fn.literal = isLiteral(ast);
13466             fn.constant = isConstant(ast);
13467             return fn;
13468           },
13469
13470           USE: 'use',
13471
13472           STRICT: 'strict',
13473
13474           watchFns: function() {
13475             var result = [];
13476             var fns = this.state.inputs;
13477             var self = this;
13478             forEach(fns, function(name) {
13479               result.push('var ' + name + '=' + self.generateFunction(name, 's'));
13480             });
13481             if (fns.length) {
13482               result.push('fn.inputs=[' + fns.join(',') + '];');
13483             }
13484             return result.join('');
13485           },
13486
13487           generateFunction: function(name, params) {
13488             return 'function(' + params + '){' +
13489                 this.varsPrefix(name) +
13490                 this.body(name) +
13491                 '};';
13492           },
13493
13494           filterPrefix: function() {
13495             var parts = [];
13496             var self = this;
13497             forEach(this.state.filters, function(id, filter) {
13498               parts.push(id + '=$filter(' + self.escape(filter) + ')');
13499             });
13500             if (parts.length) return 'var ' + parts.join(',') + ';';
13501             return '';
13502           },
13503
13504           varsPrefix: function(section) {
13505             return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
13506           },
13507
13508           body: function(section) {
13509             return this.state[section].body.join('');
13510           },
13511
13512           recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13513             var left, right, self = this, args, expression;
13514             recursionFn = recursionFn || noop;
13515             if (!skipWatchIdCheck && isDefined(ast.watchId)) {
13516               intoId = intoId || this.nextId();
13517               this.if_('i',
13518                 this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
13519                 this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
13520               );
13521               return;
13522             }
13523             switch (ast.type) {
13524             case AST.Program:
13525               forEach(ast.body, function(expression, pos) {
13526                 self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
13527                 if (pos !== ast.body.length - 1) {
13528                   self.current().body.push(right, ';');
13529                 } else {
13530                   self.return_(right);
13531                 }
13532               });
13533               break;
13534             case AST.Literal:
13535               expression = this.escape(ast.value);
13536               this.assign(intoId, expression);
13537               recursionFn(expression);
13538               break;
13539             case AST.UnaryExpression:
13540               this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
13541               expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
13542               this.assign(intoId, expression);
13543               recursionFn(expression);
13544               break;
13545             case AST.BinaryExpression:
13546               this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
13547               this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
13548               if (ast.operator === '+') {
13549                 expression = this.plus(left, right);
13550               } else if (ast.operator === '-') {
13551                 expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
13552               } else {
13553                 expression = '(' + left + ')' + ast.operator + '(' + right + ')';
13554               }
13555               this.assign(intoId, expression);
13556               recursionFn(expression);
13557               break;
13558             case AST.LogicalExpression:
13559               intoId = intoId || this.nextId();
13560               self.recurse(ast.left, intoId);
13561               self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
13562               recursionFn(intoId);
13563               break;
13564             case AST.ConditionalExpression:
13565               intoId = intoId || this.nextId();
13566               self.recurse(ast.test, intoId);
13567               self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
13568               recursionFn(intoId);
13569               break;
13570             case AST.Identifier:
13571               intoId = intoId || this.nextId();
13572               if (nameId) {
13573                 nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
13574                 nameId.computed = false;
13575                 nameId.name = ast.name;
13576               }
13577               ensureSafeMemberName(ast.name);
13578               self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
13579                 function() {
13580                   self.if_(self.stage === 'inputs' || 's', function() {
13581                     if (create && create !== 1) {
13582                       self.if_(
13583                         self.not(self.nonComputedMember('s', ast.name)),
13584                         self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
13585                     }
13586                     self.assign(intoId, self.nonComputedMember('s', ast.name));
13587                   });
13588                 }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
13589                 );
13590               if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
13591                 self.addEnsureSafeObject(intoId);
13592               }
13593               recursionFn(intoId);
13594               break;
13595             case AST.MemberExpression:
13596               left = nameId && (nameId.context = this.nextId()) || this.nextId();
13597               intoId = intoId || this.nextId();
13598               self.recurse(ast.object, left, undefined, function() {
13599                 self.if_(self.notNull(left), function() {
13600                   if (ast.computed) {
13601                     right = self.nextId();
13602                     self.recurse(ast.property, right);
13603                     self.getStringValue(right);
13604                     self.addEnsureSafeMemberName(right);
13605                     if (create && create !== 1) {
13606                       self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
13607                     }
13608                     expression = self.ensureSafeObject(self.computedMember(left, right));
13609                     self.assign(intoId, expression);
13610                     if (nameId) {
13611                       nameId.computed = true;
13612                       nameId.name = right;
13613                     }
13614                   } else {
13615                     ensureSafeMemberName(ast.property.name);
13616                     if (create && create !== 1) {
13617                       self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
13618                     }
13619                     expression = self.nonComputedMember(left, ast.property.name);
13620                     if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
13621                       expression = self.ensureSafeObject(expression);
13622                     }
13623                     self.assign(intoId, expression);
13624                     if (nameId) {
13625                       nameId.computed = false;
13626                       nameId.name = ast.property.name;
13627                     }
13628                   }
13629                 }, function() {
13630                   self.assign(intoId, 'undefined');
13631                 });
13632                 recursionFn(intoId);
13633               }, !!create);
13634               break;
13635             case AST.CallExpression:
13636               intoId = intoId || this.nextId();
13637               if (ast.filter) {
13638                 right = self.filter(ast.callee.name);
13639                 args = [];
13640                 forEach(ast.arguments, function(expr) {
13641                   var argument = self.nextId();
13642                   self.recurse(expr, argument);
13643                   args.push(argument);
13644                 });
13645                 expression = right + '(' + args.join(',') + ')';
13646                 self.assign(intoId, expression);
13647                 recursionFn(intoId);
13648               } else {
13649                 right = self.nextId();
13650                 left = {};
13651                 args = [];
13652                 self.recurse(ast.callee, right, left, function() {
13653                   self.if_(self.notNull(right), function() {
13654                     self.addEnsureSafeFunction(right);
13655                     forEach(ast.arguments, function(expr) {
13656                       self.recurse(expr, self.nextId(), undefined, function(argument) {
13657                         args.push(self.ensureSafeObject(argument));
13658                       });
13659                     });
13660                     if (left.name) {
13661                       if (!self.state.expensiveChecks) {
13662                         self.addEnsureSafeObject(left.context);
13663                       }
13664                       expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
13665                     } else {
13666                       expression = right + '(' + args.join(',') + ')';
13667                     }
13668                     expression = self.ensureSafeObject(expression);
13669                     self.assign(intoId, expression);
13670                   }, function() {
13671                     self.assign(intoId, 'undefined');
13672                   });
13673                   recursionFn(intoId);
13674                 });
13675               }
13676               break;
13677             case AST.AssignmentExpression:
13678               right = this.nextId();
13679               left = {};
13680               if (!isAssignable(ast.left)) {
13681                 throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
13682               }
13683               this.recurse(ast.left, undefined, left, function() {
13684                 self.if_(self.notNull(left.context), function() {
13685                   self.recurse(ast.right, right);
13686                   self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
13687                   self.addEnsureSafeAssignContext(left.context);
13688                   expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
13689                   self.assign(intoId, expression);
13690                   recursionFn(intoId || expression);
13691                 });
13692               }, 1);
13693               break;
13694             case AST.ArrayExpression:
13695               args = [];
13696               forEach(ast.elements, function(expr) {
13697                 self.recurse(expr, self.nextId(), undefined, function(argument) {
13698                   args.push(argument);
13699                 });
13700               });
13701               expression = '[' + args.join(',') + ']';
13702               this.assign(intoId, expression);
13703               recursionFn(expression);
13704               break;
13705             case AST.ObjectExpression:
13706               args = [];
13707               forEach(ast.properties, function(property) {
13708                 self.recurse(property.value, self.nextId(), undefined, function(expr) {
13709                   args.push(self.escape(
13710                       property.key.type === AST.Identifier ? property.key.name :
13711                         ('' + property.key.value)) +
13712                       ':' + expr);
13713                 });
13714               });
13715               expression = '{' + args.join(',') + '}';
13716               this.assign(intoId, expression);
13717               recursionFn(expression);
13718               break;
13719             case AST.ThisExpression:
13720               this.assign(intoId, 's');
13721               recursionFn('s');
13722               break;
13723             case AST.NGValueParameter:
13724               this.assign(intoId, 'v');
13725               recursionFn('v');
13726               break;
13727             }
13728           },
13729
13730           getHasOwnProperty: function(element, property) {
13731             var key = element + '.' + property;
13732             var own = this.current().own;
13733             if (!own.hasOwnProperty(key)) {
13734               own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
13735             }
13736             return own[key];
13737           },
13738
13739           assign: function(id, value) {
13740             if (!id) return;
13741             this.current().body.push(id, '=', value, ';');
13742             return id;
13743           },
13744
13745           filter: function(filterName) {
13746             if (!this.state.filters.hasOwnProperty(filterName)) {
13747               this.state.filters[filterName] = this.nextId(true);
13748             }
13749             return this.state.filters[filterName];
13750           },
13751
13752           ifDefined: function(id, defaultValue) {
13753             return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
13754           },
13755
13756           plus: function(left, right) {
13757             return 'plus(' + left + ',' + right + ')';
13758           },
13759
13760           return_: function(id) {
13761             this.current().body.push('return ', id, ';');
13762           },
13763
13764           if_: function(test, alternate, consequent) {
13765             if (test === true) {
13766               alternate();
13767             } else {
13768               var body = this.current().body;
13769               body.push('if(', test, '){');
13770               alternate();
13771               body.push('}');
13772               if (consequent) {
13773                 body.push('else{');
13774                 consequent();
13775                 body.push('}');
13776               }
13777             }
13778           },
13779
13780           not: function(expression) {
13781             return '!(' + expression + ')';
13782           },
13783
13784           notNull: function(expression) {
13785             return expression + '!=null';
13786           },
13787
13788           nonComputedMember: function(left, right) {
13789             return left + '.' + right;
13790           },
13791
13792           computedMember: function(left, right) {
13793             return left + '[' + right + ']';
13794           },
13795
13796           member: function(left, right, computed) {
13797             if (computed) return this.computedMember(left, right);
13798             return this.nonComputedMember(left, right);
13799           },
13800
13801           addEnsureSafeObject: function(item) {
13802             this.current().body.push(this.ensureSafeObject(item), ';');
13803           },
13804
13805           addEnsureSafeMemberName: function(item) {
13806             this.current().body.push(this.ensureSafeMemberName(item), ';');
13807           },
13808
13809           addEnsureSafeFunction: function(item) {
13810             this.current().body.push(this.ensureSafeFunction(item), ';');
13811           },
13812
13813           addEnsureSafeAssignContext: function(item) {
13814             this.current().body.push(this.ensureSafeAssignContext(item), ';');
13815           },
13816
13817           ensureSafeObject: function(item) {
13818             return 'ensureSafeObject(' + item + ',text)';
13819           },
13820
13821           ensureSafeMemberName: function(item) {
13822             return 'ensureSafeMemberName(' + item + ',text)';
13823           },
13824
13825           ensureSafeFunction: function(item) {
13826             return 'ensureSafeFunction(' + item + ',text)';
13827           },
13828
13829           getStringValue: function(item) {
13830             this.assign(item, 'getStringValue(' + item + ',text)');
13831           },
13832
13833           ensureSafeAssignContext: function(item) {
13834             return 'ensureSafeAssignContext(' + item + ',text)';
13835           },
13836
13837           lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13838             var self = this;
13839             return function() {
13840               self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
13841             };
13842           },
13843
13844           lazyAssign: function(id, value) {
13845             var self = this;
13846             return function() {
13847               self.assign(id, value);
13848             };
13849           },
13850
13851           stringEscapeRegex: /[^ a-zA-Z0-9]/g,
13852
13853           stringEscapeFn: function(c) {
13854             return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
13855           },
13856
13857           escape: function(value) {
13858             if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
13859             if (isNumber(value)) return value.toString();
13860             if (value === true) return 'true';
13861             if (value === false) return 'false';
13862             if (value === null) return 'null';
13863             if (typeof value === 'undefined') return 'undefined';
13864
13865             throw $parseMinErr('esc', 'IMPOSSIBLE');
13866           },
13867
13868           nextId: function(skip, init) {
13869             var id = 'v' + (this.state.nextId++);
13870             if (!skip) {
13871               this.current().vars.push(id + (init ? '=' + init : ''));
13872             }
13873             return id;
13874           },
13875
13876           current: function() {
13877             return this.state[this.state.computing];
13878           }
13879         };
13880
13881
13882         function ASTInterpreter(astBuilder, $filter) {
13883           this.astBuilder = astBuilder;
13884           this.$filter = $filter;
13885         }
13886
13887         ASTInterpreter.prototype = {
13888           compile: function(expression, expensiveChecks) {
13889             var self = this;
13890             var ast = this.astBuilder.ast(expression);
13891             this.expression = expression;
13892             this.expensiveChecks = expensiveChecks;
13893             findConstantAndWatchExpressions(ast, self.$filter);
13894             var assignable;
13895             var assign;
13896             if ((assignable = assignableAST(ast))) {
13897               assign = this.recurse(assignable);
13898             }
13899             var toWatch = getInputs(ast.body);
13900             var inputs;
13901             if (toWatch) {
13902               inputs = [];
13903               forEach(toWatch, function(watch, key) {
13904                 var input = self.recurse(watch);
13905                 watch.input = input;
13906                 inputs.push(input);
13907                 watch.watchId = key;
13908               });
13909             }
13910             var expressions = [];
13911             forEach(ast.body, function(expression) {
13912               expressions.push(self.recurse(expression.expression));
13913             });
13914             var fn = ast.body.length === 0 ? function() {} :
13915                      ast.body.length === 1 ? expressions[0] :
13916                      function(scope, locals) {
13917                        var lastValue;
13918                        forEach(expressions, function(exp) {
13919                          lastValue = exp(scope, locals);
13920                        });
13921                        return lastValue;
13922                      };
13923             if (assign) {
13924               fn.assign = function(scope, value, locals) {
13925                 return assign(scope, locals, value);
13926               };
13927             }
13928             if (inputs) {
13929               fn.inputs = inputs;
13930             }
13931             fn.literal = isLiteral(ast);
13932             fn.constant = isConstant(ast);
13933             return fn;
13934           },
13935
13936           recurse: function(ast, context, create) {
13937             var left, right, self = this, args, expression;
13938             if (ast.input) {
13939               return this.inputs(ast.input, ast.watchId);
13940             }
13941             switch (ast.type) {
13942             case AST.Literal:
13943               return this.value(ast.value, context);
13944             case AST.UnaryExpression:
13945               right = this.recurse(ast.argument);
13946               return this['unary' + ast.operator](right, context);
13947             case AST.BinaryExpression:
13948               left = this.recurse(ast.left);
13949               right = this.recurse(ast.right);
13950               return this['binary' + ast.operator](left, right, context);
13951             case AST.LogicalExpression:
13952               left = this.recurse(ast.left);
13953               right = this.recurse(ast.right);
13954               return this['binary' + ast.operator](left, right, context);
13955             case AST.ConditionalExpression:
13956               return this['ternary?:'](
13957                 this.recurse(ast.test),
13958                 this.recurse(ast.alternate),
13959                 this.recurse(ast.consequent),
13960                 context
13961               );
13962             case AST.Identifier:
13963               ensureSafeMemberName(ast.name, self.expression);
13964               return self.identifier(ast.name,
13965                                      self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
13966                                      context, create, self.expression);
13967             case AST.MemberExpression:
13968               left = this.recurse(ast.object, false, !!create);
13969               if (!ast.computed) {
13970                 ensureSafeMemberName(ast.property.name, self.expression);
13971                 right = ast.property.name;
13972               }
13973               if (ast.computed) right = this.recurse(ast.property);
13974               return ast.computed ?
13975                 this.computedMember(left, right, context, create, self.expression) :
13976                 this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
13977             case AST.CallExpression:
13978               args = [];
13979               forEach(ast.arguments, function(expr) {
13980                 args.push(self.recurse(expr));
13981               });
13982               if (ast.filter) right = this.$filter(ast.callee.name);
13983               if (!ast.filter) right = this.recurse(ast.callee, true);
13984               return ast.filter ?
13985                 function(scope, locals, assign, inputs) {
13986                   var values = [];
13987                   for (var i = 0; i < args.length; ++i) {
13988                     values.push(args[i](scope, locals, assign, inputs));
13989                   }
13990                   var value = right.apply(undefined, values, inputs);
13991                   return context ? {context: undefined, name: undefined, value: value} : value;
13992                 } :
13993                 function(scope, locals, assign, inputs) {
13994                   var rhs = right(scope, locals, assign, inputs);
13995                   var value;
13996                   if (rhs.value != null) {
13997                     ensureSafeObject(rhs.context, self.expression);
13998                     ensureSafeFunction(rhs.value, self.expression);
13999                     var values = [];
14000                     for (var i = 0; i < args.length; ++i) {
14001                       values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
14002                     }
14003                     value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
14004                   }
14005                   return context ? {value: value} : value;
14006                 };
14007             case AST.AssignmentExpression:
14008               left = this.recurse(ast.left, true, 1);
14009               right = this.recurse(ast.right);
14010               return function(scope, locals, assign, inputs) {
14011                 var lhs = left(scope, locals, assign, inputs);
14012                 var rhs = right(scope, locals, assign, inputs);
14013                 ensureSafeObject(lhs.value, self.expression);
14014                 ensureSafeAssignContext(lhs.context);
14015                 lhs.context[lhs.name] = rhs;
14016                 return context ? {value: rhs} : rhs;
14017               };
14018             case AST.ArrayExpression:
14019               args = [];
14020               forEach(ast.elements, function(expr) {
14021                 args.push(self.recurse(expr));
14022               });
14023               return function(scope, locals, assign, inputs) {
14024                 var value = [];
14025                 for (var i = 0; i < args.length; ++i) {
14026                   value.push(args[i](scope, locals, assign, inputs));
14027                 }
14028                 return context ? {value: value} : value;
14029               };
14030             case AST.ObjectExpression:
14031               args = [];
14032               forEach(ast.properties, function(property) {
14033                 args.push({key: property.key.type === AST.Identifier ?
14034                                 property.key.name :
14035                                 ('' + property.key.value),
14036                            value: self.recurse(property.value)
14037                 });
14038               });
14039               return function(scope, locals, assign, inputs) {
14040                 var value = {};
14041                 for (var i = 0; i < args.length; ++i) {
14042                   value[args[i].key] = args[i].value(scope, locals, assign, inputs);
14043                 }
14044                 return context ? {value: value} : value;
14045               };
14046             case AST.ThisExpression:
14047               return function(scope) {
14048                 return context ? {value: scope} : scope;
14049               };
14050             case AST.NGValueParameter:
14051               return function(scope, locals, assign, inputs) {
14052                 return context ? {value: assign} : assign;
14053               };
14054             }
14055           },
14056
14057           'unary+': function(argument, context) {
14058             return function(scope, locals, assign, inputs) {
14059               var arg = argument(scope, locals, assign, inputs);
14060               if (isDefined(arg)) {
14061                 arg = +arg;
14062               } else {
14063                 arg = 0;
14064               }
14065               return context ? {value: arg} : arg;
14066             };
14067           },
14068           'unary-': function(argument, context) {
14069             return function(scope, locals, assign, inputs) {
14070               var arg = argument(scope, locals, assign, inputs);
14071               if (isDefined(arg)) {
14072                 arg = -arg;
14073               } else {
14074                 arg = 0;
14075               }
14076               return context ? {value: arg} : arg;
14077             };
14078           },
14079           'unary!': function(argument, context) {
14080             return function(scope, locals, assign, inputs) {
14081               var arg = !argument(scope, locals, assign, inputs);
14082               return context ? {value: arg} : arg;
14083             };
14084           },
14085           'binary+': function(left, right, context) {
14086             return function(scope, locals, assign, inputs) {
14087               var lhs = left(scope, locals, assign, inputs);
14088               var rhs = right(scope, locals, assign, inputs);
14089               var arg = plusFn(lhs, rhs);
14090               return context ? {value: arg} : arg;
14091             };
14092           },
14093           'binary-': function(left, right, context) {
14094             return function(scope, locals, assign, inputs) {
14095               var lhs = left(scope, locals, assign, inputs);
14096               var rhs = right(scope, locals, assign, inputs);
14097               var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
14098               return context ? {value: arg} : arg;
14099             };
14100           },
14101           'binary*': function(left, right, context) {
14102             return function(scope, locals, assign, inputs) {
14103               var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
14104               return context ? {value: arg} : arg;
14105             };
14106           },
14107           'binary/': function(left, right, context) {
14108             return function(scope, locals, assign, inputs) {
14109               var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
14110               return context ? {value: arg} : arg;
14111             };
14112           },
14113           'binary%': function(left, right, context) {
14114             return function(scope, locals, assign, inputs) {
14115               var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
14116               return context ? {value: arg} : arg;
14117             };
14118           },
14119           'binary===': function(left, right, context) {
14120             return function(scope, locals, assign, inputs) {
14121               var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
14122               return context ? {value: arg} : arg;
14123             };
14124           },
14125           'binary!==': function(left, right, context) {
14126             return function(scope, locals, assign, inputs) {
14127               var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
14128               return context ? {value: arg} : arg;
14129             };
14130           },
14131           'binary==': function(left, right, context) {
14132             return function(scope, locals, assign, inputs) {
14133               var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
14134               return context ? {value: arg} : arg;
14135             };
14136           },
14137           'binary!=': function(left, right, context) {
14138             return function(scope, locals, assign, inputs) {
14139               var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
14140               return context ? {value: arg} : arg;
14141             };
14142           },
14143           'binary<': function(left, right, context) {
14144             return function(scope, locals, assign, inputs) {
14145               var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
14146               return context ? {value: arg} : arg;
14147             };
14148           },
14149           'binary>': function(left, right, context) {
14150             return function(scope, locals, assign, inputs) {
14151               var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
14152               return context ? {value: arg} : arg;
14153             };
14154           },
14155           'binary<=': function(left, right, context) {
14156             return function(scope, locals, assign, inputs) {
14157               var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
14158               return context ? {value: arg} : arg;
14159             };
14160           },
14161           'binary>=': function(left, right, context) {
14162             return function(scope, locals, assign, inputs) {
14163               var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
14164               return context ? {value: arg} : arg;
14165             };
14166           },
14167           'binary&&': function(left, right, context) {
14168             return function(scope, locals, assign, inputs) {
14169               var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
14170               return context ? {value: arg} : arg;
14171             };
14172           },
14173           'binary||': function(left, right, context) {
14174             return function(scope, locals, assign, inputs) {
14175               var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
14176               return context ? {value: arg} : arg;
14177             };
14178           },
14179           'ternary?:': function(test, alternate, consequent, context) {
14180             return function(scope, locals, assign, inputs) {
14181               var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
14182               return context ? {value: arg} : arg;
14183             };
14184           },
14185           value: function(value, context) {
14186             return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
14187           },
14188           identifier: function(name, expensiveChecks, context, create, expression) {
14189             return function(scope, locals, assign, inputs) {
14190               var base = locals && (name in locals) ? locals : scope;
14191               if (create && create !== 1 && base && !(base[name])) {
14192                 base[name] = {};
14193               }
14194               var value = base ? base[name] : undefined;
14195               if (expensiveChecks) {
14196                 ensureSafeObject(value, expression);
14197               }
14198               if (context) {
14199                 return {context: base, name: name, value: value};
14200               } else {
14201                 return value;
14202               }
14203             };
14204           },
14205           computedMember: function(left, right, context, create, expression) {
14206             return function(scope, locals, assign, inputs) {
14207               var lhs = left(scope, locals, assign, inputs);
14208               var rhs;
14209               var value;
14210               if (lhs != null) {
14211                 rhs = right(scope, locals, assign, inputs);
14212                 rhs = getStringValue(rhs);
14213                 ensureSafeMemberName(rhs, expression);
14214                 if (create && create !== 1 && lhs && !(lhs[rhs])) {
14215                   lhs[rhs] = {};
14216                 }
14217                 value = lhs[rhs];
14218                 ensureSafeObject(value, expression);
14219               }
14220               if (context) {
14221                 return {context: lhs, name: rhs, value: value};
14222               } else {
14223                 return value;
14224               }
14225             };
14226           },
14227           nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
14228             return function(scope, locals, assign, inputs) {
14229               var lhs = left(scope, locals, assign, inputs);
14230               if (create && create !== 1 && lhs && !(lhs[right])) {
14231                 lhs[right] = {};
14232               }
14233               var value = lhs != null ? lhs[right] : undefined;
14234               if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
14235                 ensureSafeObject(value, expression);
14236               }
14237               if (context) {
14238                 return {context: lhs, name: right, value: value};
14239               } else {
14240                 return value;
14241               }
14242             };
14243           },
14244           inputs: function(input, watchId) {
14245             return function(scope, value, locals, inputs) {
14246               if (inputs) return inputs[watchId];
14247               return input(scope, value, locals);
14248             };
14249           }
14250         };
14251
14252         /**
14253          * @constructor
14254          */
14255         var Parser = function(lexer, $filter, options) {
14256           this.lexer = lexer;
14257           this.$filter = $filter;
14258           this.options = options;
14259           this.ast = new AST(this.lexer);
14260           this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
14261                                            new ASTCompiler(this.ast, $filter);
14262         };
14263
14264         Parser.prototype = {
14265           constructor: Parser,
14266
14267           parse: function(text) {
14268             return this.astCompiler.compile(text, this.options.expensiveChecks);
14269           }
14270         };
14271
14272         var getterFnCacheDefault = createMap();
14273         var getterFnCacheExpensive = createMap();
14274
14275         function isPossiblyDangerousMemberName(name) {
14276           return name == 'constructor';
14277         }
14278
14279         var objectValueOf = Object.prototype.valueOf;
14280
14281         function getValueOf(value) {
14282           return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
14283         }
14284
14285         ///////////////////////////////////
14286
14287         /**
14288          * @ngdoc service
14289          * @name $parse
14290          * @kind function
14291          *
14292          * @description
14293          *
14294          * Converts Angular {@link guide/expression expression} into a function.
14295          *
14296          * ```js
14297          *   var getter = $parse('user.name');
14298          *   var setter = getter.assign;
14299          *   var context = {user:{name:'angular'}};
14300          *   var locals = {user:{name:'local'}};
14301          *
14302          *   expect(getter(context)).toEqual('angular');
14303          *   setter(context, 'newValue');
14304          *   expect(context.user.name).toEqual('newValue');
14305          *   expect(getter(context, locals)).toEqual('local');
14306          * ```
14307          *
14308          *
14309          * @param {string} expression String expression to compile.
14310          * @returns {function(context, locals)} a function which represents the compiled expression:
14311          *
14312          *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14313          *      are evaluated against (typically a scope object).
14314          *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14315          *      `context`.
14316          *
14317          *    The returned function also has the following properties:
14318          *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
14319          *        literal.
14320          *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
14321          *        constant literals.
14322          *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
14323          *        set to a function to change its value on the given context.
14324          *
14325          */
14326
14327
14328         /**
14329          * @ngdoc provider
14330          * @name $parseProvider
14331          *
14332          * @description
14333          * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
14334          *  service.
14335          */
14336         function $ParseProvider() {
14337           var cacheDefault = createMap();
14338           var cacheExpensive = createMap();
14339
14340           this.$get = ['$filter', function($filter) {
14341             var noUnsafeEval = csp().noUnsafeEval;
14342             var $parseOptions = {
14343                   csp: noUnsafeEval,
14344                   expensiveChecks: false
14345                 },
14346                 $parseOptionsExpensive = {
14347                   csp: noUnsafeEval,
14348                   expensiveChecks: true
14349                 };
14350
14351             return function $parse(exp, interceptorFn, expensiveChecks) {
14352               var parsedExpression, oneTime, cacheKey;
14353
14354               switch (typeof exp) {
14355                 case 'string':
14356                   exp = exp.trim();
14357                   cacheKey = exp;
14358
14359                   var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
14360                   parsedExpression = cache[cacheKey];
14361
14362                   if (!parsedExpression) {
14363                     if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
14364                       oneTime = true;
14365                       exp = exp.substring(2);
14366                     }
14367                     var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
14368                     var lexer = new Lexer(parseOptions);
14369                     var parser = new Parser(lexer, $filter, parseOptions);
14370                     parsedExpression = parser.parse(exp);
14371                     if (parsedExpression.constant) {
14372                       parsedExpression.$$watchDelegate = constantWatchDelegate;
14373                     } else if (oneTime) {
14374                       parsedExpression.$$watchDelegate = parsedExpression.literal ?
14375                           oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
14376                     } else if (parsedExpression.inputs) {
14377                       parsedExpression.$$watchDelegate = inputsWatchDelegate;
14378                     }
14379                     cache[cacheKey] = parsedExpression;
14380                   }
14381                   return addInterceptor(parsedExpression, interceptorFn);
14382
14383                 case 'function':
14384                   return addInterceptor(exp, interceptorFn);
14385
14386                 default:
14387                   return noop;
14388               }
14389             };
14390
14391             function expressionInputDirtyCheck(newValue, oldValueOfValue) {
14392
14393               if (newValue == null || oldValueOfValue == null) { // null/undefined
14394                 return newValue === oldValueOfValue;
14395               }
14396
14397               if (typeof newValue === 'object') {
14398
14399                 // attempt to convert the value to a primitive type
14400                 // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
14401                 //             be cheaply dirty-checked
14402                 newValue = getValueOf(newValue);
14403
14404                 if (typeof newValue === 'object') {
14405                   // objects/arrays are not supported - deep-watching them would be too expensive
14406                   return false;
14407                 }
14408
14409                 // fall-through to the primitive equality check
14410               }
14411
14412               //Primitive or NaN
14413               return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
14414             }
14415
14416             function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
14417               var inputExpressions = parsedExpression.inputs;
14418               var lastResult;
14419
14420               if (inputExpressions.length === 1) {
14421                 var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
14422                 inputExpressions = inputExpressions[0];
14423                 return scope.$watch(function expressionInputWatch(scope) {
14424                   var newInputValue = inputExpressions(scope);
14425                   if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
14426                     lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
14427                     oldInputValueOf = newInputValue && getValueOf(newInputValue);
14428                   }
14429                   return lastResult;
14430                 }, listener, objectEquality, prettyPrintExpression);
14431               }
14432
14433               var oldInputValueOfValues = [];
14434               var oldInputValues = [];
14435               for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14436                 oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
14437                 oldInputValues[i] = null;
14438               }
14439
14440               return scope.$watch(function expressionInputsWatch(scope) {
14441                 var changed = false;
14442
14443                 for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14444                   var newInputValue = inputExpressions[i](scope);
14445                   if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
14446                     oldInputValues[i] = newInputValue;
14447                     oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
14448                   }
14449                 }
14450
14451                 if (changed) {
14452                   lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
14453                 }
14454
14455                 return lastResult;
14456               }, listener, objectEquality, prettyPrintExpression);
14457             }
14458
14459             function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14460               var unwatch, lastValue;
14461               return unwatch = scope.$watch(function oneTimeWatch(scope) {
14462                 return parsedExpression(scope);
14463               }, function oneTimeListener(value, old, scope) {
14464                 lastValue = value;
14465                 if (isFunction(listener)) {
14466                   listener.apply(this, arguments);
14467                 }
14468                 if (isDefined(value)) {
14469                   scope.$$postDigest(function() {
14470                     if (isDefined(lastValue)) {
14471                       unwatch();
14472                     }
14473                   });
14474                 }
14475               }, objectEquality);
14476             }
14477
14478             function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14479               var unwatch, lastValue;
14480               return unwatch = scope.$watch(function oneTimeWatch(scope) {
14481                 return parsedExpression(scope);
14482               }, function oneTimeListener(value, old, scope) {
14483                 lastValue = value;
14484                 if (isFunction(listener)) {
14485                   listener.call(this, value, old, scope);
14486                 }
14487                 if (isAllDefined(value)) {
14488                   scope.$$postDigest(function() {
14489                     if (isAllDefined(lastValue)) unwatch();
14490                   });
14491                 }
14492               }, objectEquality);
14493
14494               function isAllDefined(value) {
14495                 var allDefined = true;
14496                 forEach(value, function(val) {
14497                   if (!isDefined(val)) allDefined = false;
14498                 });
14499                 return allDefined;
14500               }
14501             }
14502
14503             function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14504               var unwatch;
14505               return unwatch = scope.$watch(function constantWatch(scope) {
14506                 return parsedExpression(scope);
14507               }, function constantListener(value, old, scope) {
14508                 if (isFunction(listener)) {
14509                   listener.apply(this, arguments);
14510                 }
14511                 unwatch();
14512               }, objectEquality);
14513             }
14514
14515             function addInterceptor(parsedExpression, interceptorFn) {
14516               if (!interceptorFn) return parsedExpression;
14517               var watchDelegate = parsedExpression.$$watchDelegate;
14518               var useInputs = false;
14519
14520               var regularWatch =
14521                   watchDelegate !== oneTimeLiteralWatchDelegate &&
14522                   watchDelegate !== oneTimeWatchDelegate;
14523
14524               var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
14525                 var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
14526                 return interceptorFn(value, scope, locals);
14527               } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
14528                 var value = parsedExpression(scope, locals, assign, inputs);
14529                 var result = interceptorFn(value, scope, locals);
14530                 // we only return the interceptor's result if the
14531                 // initial value is defined (for bind-once)
14532                 return isDefined(value) ? result : value;
14533               };
14534
14535               // Propagate $$watchDelegates other then inputsWatchDelegate
14536               if (parsedExpression.$$watchDelegate &&
14537                   parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
14538                 fn.$$watchDelegate = parsedExpression.$$watchDelegate;
14539               } else if (!interceptorFn.$stateful) {
14540                 // If there is an interceptor, but no watchDelegate then treat the interceptor like
14541                 // we treat filters - it is assumed to be a pure function unless flagged with $stateful
14542                 fn.$$watchDelegate = inputsWatchDelegate;
14543                 useInputs = !parsedExpression.inputs;
14544                 fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
14545               }
14546
14547               return fn;
14548             }
14549           }];
14550         }
14551
14552         /**
14553          * @ngdoc service
14554          * @name $q
14555          * @requires $rootScope
14556          *
14557          * @description
14558          * A service that helps you run functions asynchronously, and use their return values (or exceptions)
14559          * when they are done processing.
14560          *
14561          * This is an implementation of promises/deferred objects inspired by
14562          * [Kris Kowal's Q](https://github.com/kriskowal/q).
14563          *
14564          * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
14565          * implementations, and the other which resembles ES6 promises to some degree.
14566          *
14567          * # $q constructor
14568          *
14569          * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
14570          * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
14571          * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
14572          *
14573          * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
14574          * available yet.
14575          *
14576          * It can be used like so:
14577          *
14578          * ```js
14579          *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14580          *   // are available in the current lexical scope (they could have been injected or passed in).
14581          *
14582          *   function asyncGreet(name) {
14583          *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
14584          *     return $q(function(resolve, reject) {
14585          *       setTimeout(function() {
14586          *         if (okToGreet(name)) {
14587          *           resolve('Hello, ' + name + '!');
14588          *         } else {
14589          *           reject('Greeting ' + name + ' is not allowed.');
14590          *         }
14591          *       }, 1000);
14592          *     });
14593          *   }
14594          *
14595          *   var promise = asyncGreet('Robin Hood');
14596          *   promise.then(function(greeting) {
14597          *     alert('Success: ' + greeting);
14598          *   }, function(reason) {
14599          *     alert('Failed: ' + reason);
14600          *   });
14601          * ```
14602          *
14603          * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
14604          *
14605          * Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
14606          *
14607          * However, the more traditional CommonJS-style usage is still available, and documented below.
14608          *
14609          * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
14610          * interface for interacting with an object that represents the result of an action that is
14611          * performed asynchronously, and may or may not be finished at any given point in time.
14612          *
14613          * From the perspective of dealing with error handling, deferred and promise APIs are to
14614          * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
14615          *
14616          * ```js
14617          *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14618          *   // are available in the current lexical scope (they could have been injected or passed in).
14619          *
14620          *   function asyncGreet(name) {
14621          *     var deferred = $q.defer();
14622          *
14623          *     setTimeout(function() {
14624          *       deferred.notify('About to greet ' + name + '.');
14625          *
14626          *       if (okToGreet(name)) {
14627          *         deferred.resolve('Hello, ' + name + '!');
14628          *       } else {
14629          *         deferred.reject('Greeting ' + name + ' is not allowed.');
14630          *       }
14631          *     }, 1000);
14632          *
14633          *     return deferred.promise;
14634          *   }
14635          *
14636          *   var promise = asyncGreet('Robin Hood');
14637          *   promise.then(function(greeting) {
14638          *     alert('Success: ' + greeting);
14639          *   }, function(reason) {
14640          *     alert('Failed: ' + reason);
14641          *   }, function(update) {
14642          *     alert('Got notification: ' + update);
14643          *   });
14644          * ```
14645          *
14646          * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
14647          * comes in the way of guarantees that promise and deferred APIs make, see
14648          * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
14649          *
14650          * Additionally the promise api allows for composition that is very hard to do with the
14651          * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
14652          * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
14653          * section on serial or parallel joining of promises.
14654          *
14655          * # The Deferred API
14656          *
14657          * A new instance of deferred is constructed by calling `$q.defer()`.
14658          *
14659          * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
14660          * that can be used for signaling the successful or unsuccessful completion, as well as the status
14661          * of the task.
14662          *
14663          * **Methods**
14664          *
14665          * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
14666          *   constructed via `$q.reject`, the promise will be rejected instead.
14667          * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
14668          *   resolving it with a rejection constructed via `$q.reject`.
14669          * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
14670          *   multiple times before the promise is either resolved or rejected.
14671          *
14672          * **Properties**
14673          *
14674          * - promise – `{Promise}` – promise object associated with this deferred.
14675          *
14676          *
14677          * # The Promise API
14678          *
14679          * A new promise instance is created when a deferred instance is created and can be retrieved by
14680          * calling `deferred.promise`.
14681          *
14682          * The purpose of the promise object is to allow for interested parties to get access to the result
14683          * of the deferred task when it completes.
14684          *
14685          * **Methods**
14686          *
14687          * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
14688          *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
14689          *   as soon as the result is available. The callbacks are called with a single argument: the result
14690          *   or rejection reason. Additionally, the notify callback may be called zero or more times to
14691          *   provide a progress indication, before the promise is resolved or rejected.
14692          *
14693          *   This method *returns a new promise* which is resolved or rejected via the return value of the
14694          *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
14695          *   with the value which is resolved in that promise using
14696          *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
14697          *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
14698          *   resolved or rejected from the notifyCallback method.
14699          *
14700          * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
14701          *
14702          * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
14703          *   but to do so without modifying the final value. This is useful to release resources or do some
14704          *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
14705          *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
14706          *   more information.
14707          *
14708          * # Chaining promises
14709          *
14710          * Because calling the `then` method of a promise returns a new derived promise, it is easily
14711          * possible to create a chain of promises:
14712          *
14713          * ```js
14714          *   promiseB = promiseA.then(function(result) {
14715          *     return result + 1;
14716          *   });
14717          *
14718          *   // promiseB will be resolved immediately after promiseA is resolved and its value
14719          *   // will be the result of promiseA incremented by 1
14720          * ```
14721          *
14722          * It is possible to create chains of any length and since a promise can be resolved with another
14723          * promise (which will defer its resolution further), it is possible to pause/defer resolution of
14724          * the promises at any point in the chain. This makes it possible to implement powerful APIs like
14725          * $http's response interceptors.
14726          *
14727          *
14728          * # Differences between Kris Kowal's Q and $q
14729          *
14730          *  There are two main differences:
14731          *
14732          * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
14733          *   mechanism in angular, which means faster propagation of resolution or rejection into your
14734          *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
14735          * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
14736          *   all the important functionality needed for common async tasks.
14737          *
14738          *  # Testing
14739          *
14740          *  ```js
14741          *    it('should simulate promise', inject(function($q, $rootScope) {
14742          *      var deferred = $q.defer();
14743          *      var promise = deferred.promise;
14744          *      var resolvedValue;
14745          *
14746          *      promise.then(function(value) { resolvedValue = value; });
14747          *      expect(resolvedValue).toBeUndefined();
14748          *
14749          *      // Simulate resolving of promise
14750          *      deferred.resolve(123);
14751          *      // Note that the 'then' function does not get called synchronously.
14752          *      // This is because we want the promise API to always be async, whether or not
14753          *      // it got called synchronously or asynchronously.
14754          *      expect(resolvedValue).toBeUndefined();
14755          *
14756          *      // Propagate promise resolution to 'then' functions using $apply().
14757          *      $rootScope.$apply();
14758          *      expect(resolvedValue).toEqual(123);
14759          *    }));
14760          *  ```
14761          *
14762          * @param {function(function, function)} resolver Function which is responsible for resolving or
14763          *   rejecting the newly created promise. The first parameter is a function which resolves the
14764          *   promise, the second parameter is a function which rejects the promise.
14765          *
14766          * @returns {Promise} The newly created promise.
14767          */
14768         function $QProvider() {
14769
14770           this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
14771             return qFactory(function(callback) {
14772               $rootScope.$evalAsync(callback);
14773             }, $exceptionHandler);
14774           }];
14775         }
14776
14777         function $$QProvider() {
14778           this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
14779             return qFactory(function(callback) {
14780               $browser.defer(callback);
14781             }, $exceptionHandler);
14782           }];
14783         }
14784
14785         /**
14786          * Constructs a promise manager.
14787          *
14788          * @param {function(function)} nextTick Function for executing functions in the next turn.
14789          * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
14790          *     debugging purposes.
14791          * @returns {object} Promise manager.
14792          */
14793         function qFactory(nextTick, exceptionHandler) {
14794           var $qMinErr = minErr('$q', TypeError);
14795           function callOnce(self, resolveFn, rejectFn) {
14796             var called = false;
14797             function wrap(fn) {
14798               return function(value) {
14799                 if (called) return;
14800                 called = true;
14801                 fn.call(self, value);
14802               };
14803             }
14804
14805             return [wrap(resolveFn), wrap(rejectFn)];
14806           }
14807
14808           /**
14809            * @ngdoc method
14810            * @name ng.$q#defer
14811            * @kind function
14812            *
14813            * @description
14814            * Creates a `Deferred` object which represents a task which will finish in the future.
14815            *
14816            * @returns {Deferred} Returns a new instance of deferred.
14817            */
14818           var defer = function() {
14819             return new Deferred();
14820           };
14821
14822           function Promise() {
14823             this.$$state = { status: 0 };
14824           }
14825
14826           extend(Promise.prototype, {
14827             then: function(onFulfilled, onRejected, progressBack) {
14828               if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
14829                 return this;
14830               }
14831               var result = new Deferred();
14832
14833               this.$$state.pending = this.$$state.pending || [];
14834               this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
14835               if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
14836
14837               return result.promise;
14838             },
14839
14840             "catch": function(callback) {
14841               return this.then(null, callback);
14842             },
14843
14844             "finally": function(callback, progressBack) {
14845               return this.then(function(value) {
14846                 return handleCallback(value, true, callback);
14847               }, function(error) {
14848                 return handleCallback(error, false, callback);
14849               }, progressBack);
14850             }
14851           });
14852
14853           //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
14854           function simpleBind(context, fn) {
14855             return function(value) {
14856               fn.call(context, value);
14857             };
14858           }
14859
14860           function processQueue(state) {
14861             var fn, deferred, pending;
14862
14863             pending = state.pending;
14864             state.processScheduled = false;
14865             state.pending = undefined;
14866             for (var i = 0, ii = pending.length; i < ii; ++i) {
14867               deferred = pending[i][0];
14868               fn = pending[i][state.status];
14869               try {
14870                 if (isFunction(fn)) {
14871                   deferred.resolve(fn(state.value));
14872                 } else if (state.status === 1) {
14873                   deferred.resolve(state.value);
14874                 } else {
14875                   deferred.reject(state.value);
14876                 }
14877               } catch (e) {
14878                 deferred.reject(e);
14879                 exceptionHandler(e);
14880               }
14881             }
14882           }
14883
14884           function scheduleProcessQueue(state) {
14885             if (state.processScheduled || !state.pending) return;
14886             state.processScheduled = true;
14887             nextTick(function() { processQueue(state); });
14888           }
14889
14890           function Deferred() {
14891             this.promise = new Promise();
14892             //Necessary to support unbound execution :/
14893             this.resolve = simpleBind(this, this.resolve);
14894             this.reject = simpleBind(this, this.reject);
14895             this.notify = simpleBind(this, this.notify);
14896           }
14897
14898           extend(Deferred.prototype, {
14899             resolve: function(val) {
14900               if (this.promise.$$state.status) return;
14901               if (val === this.promise) {
14902                 this.$$reject($qMinErr(
14903                   'qcycle',
14904                   "Expected promise to be resolved with value other than itself '{0}'",
14905                   val));
14906               } else {
14907                 this.$$resolve(val);
14908               }
14909
14910             },
14911
14912             $$resolve: function(val) {
14913               var then, fns;
14914
14915               fns = callOnce(this, this.$$resolve, this.$$reject);
14916               try {
14917                 if ((isObject(val) || isFunction(val))) then = val && val.then;
14918                 if (isFunction(then)) {
14919                   this.promise.$$state.status = -1;
14920                   then.call(val, fns[0], fns[1], this.notify);
14921                 } else {
14922                   this.promise.$$state.value = val;
14923                   this.promise.$$state.status = 1;
14924                   scheduleProcessQueue(this.promise.$$state);
14925                 }
14926               } catch (e) {
14927                 fns[1](e);
14928                 exceptionHandler(e);
14929               }
14930             },
14931
14932             reject: function(reason) {
14933               if (this.promise.$$state.status) return;
14934               this.$$reject(reason);
14935             },
14936
14937             $$reject: function(reason) {
14938               this.promise.$$state.value = reason;
14939               this.promise.$$state.status = 2;
14940               scheduleProcessQueue(this.promise.$$state);
14941             },
14942
14943             notify: function(progress) {
14944               var callbacks = this.promise.$$state.pending;
14945
14946               if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
14947                 nextTick(function() {
14948                   var callback, result;
14949                   for (var i = 0, ii = callbacks.length; i < ii; i++) {
14950                     result = callbacks[i][0];
14951                     callback = callbacks[i][3];
14952                     try {
14953                       result.notify(isFunction(callback) ? callback(progress) : progress);
14954                     } catch (e) {
14955                       exceptionHandler(e);
14956                     }
14957                   }
14958                 });
14959               }
14960             }
14961           });
14962
14963           /**
14964            * @ngdoc method
14965            * @name $q#reject
14966            * @kind function
14967            *
14968            * @description
14969            * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
14970            * used to forward rejection in a chain of promises. If you are dealing with the last promise in
14971            * a promise chain, you don't need to worry about it.
14972            *
14973            * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
14974            * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
14975            * a promise error callback and you want to forward the error to the promise derived from the
14976            * current promise, you have to "rethrow" the error by returning a rejection constructed via
14977            * `reject`.
14978            *
14979            * ```js
14980            *   promiseB = promiseA.then(function(result) {
14981            *     // success: do something and resolve promiseB
14982            *     //          with the old or a new result
14983            *     return result;
14984            *   }, function(reason) {
14985            *     // error: handle the error if possible and
14986            *     //        resolve promiseB with newPromiseOrValue,
14987            *     //        otherwise forward the rejection to promiseB
14988            *     if (canHandle(reason)) {
14989            *      // handle the error and recover
14990            *      return newPromiseOrValue;
14991            *     }
14992            *     return $q.reject(reason);
14993            *   });
14994            * ```
14995            *
14996            * @param {*} reason Constant, message, exception or an object representing the rejection reason.
14997            * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
14998            */
14999           var reject = function(reason) {
15000             var result = new Deferred();
15001             result.reject(reason);
15002             return result.promise;
15003           };
15004
15005           var makePromise = function makePromise(value, resolved) {
15006             var result = new Deferred();
15007             if (resolved) {
15008               result.resolve(value);
15009             } else {
15010               result.reject(value);
15011             }
15012             return result.promise;
15013           };
15014
15015           var handleCallback = function handleCallback(value, isResolved, callback) {
15016             var callbackOutput = null;
15017             try {
15018               if (isFunction(callback)) callbackOutput = callback();
15019             } catch (e) {
15020               return makePromise(e, false);
15021             }
15022             if (isPromiseLike(callbackOutput)) {
15023               return callbackOutput.then(function() {
15024                 return makePromise(value, isResolved);
15025               }, function(error) {
15026                 return makePromise(error, false);
15027               });
15028             } else {
15029               return makePromise(value, isResolved);
15030             }
15031           };
15032
15033           /**
15034            * @ngdoc method
15035            * @name $q#when
15036            * @kind function
15037            *
15038            * @description
15039            * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
15040            * This is useful when you are dealing with an object that might or might not be a promise, or if
15041            * the promise comes from a source that can't be trusted.
15042            *
15043            * @param {*} value Value or a promise
15044            * @param {Function=} successCallback
15045            * @param {Function=} errorCallback
15046            * @param {Function=} progressCallback
15047            * @returns {Promise} Returns a promise of the passed value or promise
15048            */
15049
15050
15051           var when = function(value, callback, errback, progressBack) {
15052             var result = new Deferred();
15053             result.resolve(value);
15054             return result.promise.then(callback, errback, progressBack);
15055           };
15056
15057           /**
15058            * @ngdoc method
15059            * @name $q#resolve
15060            * @kind function
15061            *
15062            * @description
15063            * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
15064            *
15065            * @param {*} value Value or a promise
15066            * @param {Function=} successCallback
15067            * @param {Function=} errorCallback
15068            * @param {Function=} progressCallback
15069            * @returns {Promise} Returns a promise of the passed value or promise
15070            */
15071           var resolve = when;
15072
15073           /**
15074            * @ngdoc method
15075            * @name $q#all
15076            * @kind function
15077            *
15078            * @description
15079            * Combines multiple promises into a single promise that is resolved when all of the input
15080            * promises are resolved.
15081            *
15082            * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
15083            * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
15084            *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
15085            *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
15086            *   with the same rejection value.
15087            */
15088
15089           function all(promises) {
15090             var deferred = new Deferred(),
15091                 counter = 0,
15092                 results = isArray(promises) ? [] : {};
15093
15094             forEach(promises, function(promise, key) {
15095               counter++;
15096               when(promise).then(function(value) {
15097                 if (results.hasOwnProperty(key)) return;
15098                 results[key] = value;
15099                 if (!(--counter)) deferred.resolve(results);
15100               }, function(reason) {
15101                 if (results.hasOwnProperty(key)) return;
15102                 deferred.reject(reason);
15103               });
15104             });
15105
15106             if (counter === 0) {
15107               deferred.resolve(results);
15108             }
15109
15110             return deferred.promise;
15111           }
15112
15113           var $Q = function Q(resolver) {
15114             if (!isFunction(resolver)) {
15115               throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
15116             }
15117
15118             if (!(this instanceof Q)) {
15119               // More useful when $Q is the Promise itself.
15120               return new Q(resolver);
15121             }
15122
15123             var deferred = new Deferred();
15124
15125             function resolveFn(value) {
15126               deferred.resolve(value);
15127             }
15128
15129             function rejectFn(reason) {
15130               deferred.reject(reason);
15131             }
15132
15133             resolver(resolveFn, rejectFn);
15134
15135             return deferred.promise;
15136           };
15137
15138           $Q.defer = defer;
15139           $Q.reject = reject;
15140           $Q.when = when;
15141           $Q.resolve = resolve;
15142           $Q.all = all;
15143
15144           return $Q;
15145         }
15146
15147         function $$RAFProvider() { //rAF
15148           this.$get = ['$window', '$timeout', function($window, $timeout) {
15149             var requestAnimationFrame = $window.requestAnimationFrame ||
15150                                         $window.webkitRequestAnimationFrame;
15151
15152             var cancelAnimationFrame = $window.cancelAnimationFrame ||
15153                                        $window.webkitCancelAnimationFrame ||
15154                                        $window.webkitCancelRequestAnimationFrame;
15155
15156             var rafSupported = !!requestAnimationFrame;
15157             var raf = rafSupported
15158               ? function(fn) {
15159                   var id = requestAnimationFrame(fn);
15160                   return function() {
15161                     cancelAnimationFrame(id);
15162                   };
15163                 }
15164               : function(fn) {
15165                   var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
15166                   return function() {
15167                     $timeout.cancel(timer);
15168                   };
15169                 };
15170
15171             raf.supported = rafSupported;
15172
15173             return raf;
15174           }];
15175         }
15176
15177         /**
15178          * DESIGN NOTES
15179          *
15180          * The design decisions behind the scope are heavily favored for speed and memory consumption.
15181          *
15182          * The typical use of scope is to watch the expressions, which most of the time return the same
15183          * value as last time so we optimize the operation.
15184          *
15185          * Closures construction is expensive in terms of speed as well as memory:
15186          *   - No closures, instead use prototypical inheritance for API
15187          *   - Internal state needs to be stored on scope directly, which means that private state is
15188          *     exposed as $$____ properties
15189          *
15190          * Loop operations are optimized by using while(count--) { ... }
15191          *   - This means that in order to keep the same order of execution as addition we have to add
15192          *     items to the array at the beginning (unshift) instead of at the end (push)
15193          *
15194          * Child scopes are created and removed often
15195          *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
15196          *
15197          * There are fewer watches than observers. This is why you don't want the observer to be implemented
15198          * in the same way as watch. Watch requires return of the initialization function which is expensive
15199          * to construct.
15200          */
15201
15202
15203         /**
15204          * @ngdoc provider
15205          * @name $rootScopeProvider
15206          * @description
15207          *
15208          * Provider for the $rootScope service.
15209          */
15210
15211         /**
15212          * @ngdoc method
15213          * @name $rootScopeProvider#digestTtl
15214          * @description
15215          *
15216          * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
15217          * assuming that the model is unstable.
15218          *
15219          * The current default is 10 iterations.
15220          *
15221          * In complex applications it's possible that the dependencies between `$watch`s will result in
15222          * several digest iterations. However if an application needs more than the default 10 digest
15223          * iterations for its model to stabilize then you should investigate what is causing the model to
15224          * continuously change during the digest.
15225          *
15226          * Increasing the TTL could have performance implications, so you should not change it without
15227          * proper justification.
15228          *
15229          * @param {number} limit The number of digest iterations.
15230          */
15231
15232
15233         /**
15234          * @ngdoc service
15235          * @name $rootScope
15236          * @description
15237          *
15238          * Every application has a single root {@link ng.$rootScope.Scope scope}.
15239          * All other scopes are descendant scopes of the root scope. Scopes provide separation
15240          * between the model and the view, via a mechanism for watching the model for changes.
15241          * They also provide event emission/broadcast and subscription facility. See the
15242          * {@link guide/scope developer guide on scopes}.
15243          */
15244         function $RootScopeProvider() {
15245           var TTL = 10;
15246           var $rootScopeMinErr = minErr('$rootScope');
15247           var lastDirtyWatch = null;
15248           var applyAsyncId = null;
15249
15250           this.digestTtl = function(value) {
15251             if (arguments.length) {
15252               TTL = value;
15253             }
15254             return TTL;
15255           };
15256
15257           function createChildScopeClass(parent) {
15258             function ChildScope() {
15259               this.$$watchers = this.$$nextSibling =
15260                   this.$$childHead = this.$$childTail = null;
15261               this.$$listeners = {};
15262               this.$$listenerCount = {};
15263               this.$$watchersCount = 0;
15264               this.$id = nextUid();
15265               this.$$ChildScope = null;
15266             }
15267             ChildScope.prototype = parent;
15268             return ChildScope;
15269           }
15270
15271           this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
15272               function($injector, $exceptionHandler, $parse, $browser) {
15273
15274             function destroyChildScope($event) {
15275                 $event.currentScope.$$destroyed = true;
15276             }
15277
15278             function cleanUpScope($scope) {
15279
15280               if (msie === 9) {
15281                 // There is a memory leak in IE9 if all child scopes are not disconnected
15282                 // completely when a scope is destroyed. So this code will recurse up through
15283                 // all this scopes children
15284                 //
15285                 // See issue https://github.com/angular/angular.js/issues/10706
15286                 $scope.$$childHead && cleanUpScope($scope.$$childHead);
15287                 $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
15288               }
15289
15290               // The code below works around IE9 and V8's memory leaks
15291               //
15292               // See:
15293               // - https://code.google.com/p/v8/issues/detail?id=2073#c26
15294               // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
15295               // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
15296
15297               $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
15298                   $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
15299             }
15300
15301             /**
15302              * @ngdoc type
15303              * @name $rootScope.Scope
15304              *
15305              * @description
15306              * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
15307              * {@link auto.$injector $injector}. Child scopes are created using the
15308              * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
15309              * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
15310              * an in-depth introduction and usage examples.
15311              *
15312              *
15313              * # Inheritance
15314              * A scope can inherit from a parent scope, as in this example:
15315              * ```js
15316                  var parent = $rootScope;
15317                  var child = parent.$new();
15318
15319                  parent.salutation = "Hello";
15320                  expect(child.salutation).toEqual('Hello');
15321
15322                  child.salutation = "Welcome";
15323                  expect(child.salutation).toEqual('Welcome');
15324                  expect(parent.salutation).toEqual('Hello');
15325              * ```
15326              *
15327              * When interacting with `Scope` in tests, additional helper methods are available on the
15328              * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
15329              * details.
15330              *
15331              *
15332              * @param {Object.<string, function()>=} providers Map of service factory which need to be
15333              *                                       provided for the current scope. Defaults to {@link ng}.
15334              * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
15335              *                              append/override services provided by `providers`. This is handy
15336              *                              when unit-testing and having the need to override a default
15337              *                              service.
15338              * @returns {Object} Newly created scope.
15339              *
15340              */
15341             function Scope() {
15342               this.$id = nextUid();
15343               this.$$phase = this.$parent = this.$$watchers =
15344                              this.$$nextSibling = this.$$prevSibling =
15345                              this.$$childHead = this.$$childTail = null;
15346               this.$root = this;
15347               this.$$destroyed = false;
15348               this.$$listeners = {};
15349               this.$$listenerCount = {};
15350               this.$$watchersCount = 0;
15351               this.$$isolateBindings = null;
15352             }
15353
15354             /**
15355              * @ngdoc property
15356              * @name $rootScope.Scope#$id
15357              *
15358              * @description
15359              * Unique scope ID (monotonically increasing) useful for debugging.
15360              */
15361
15362              /**
15363               * @ngdoc property
15364               * @name $rootScope.Scope#$parent
15365               *
15366               * @description
15367               * Reference to the parent scope.
15368               */
15369
15370               /**
15371                * @ngdoc property
15372                * @name $rootScope.Scope#$root
15373                *
15374                * @description
15375                * Reference to the root scope.
15376                */
15377
15378             Scope.prototype = {
15379               constructor: Scope,
15380               /**
15381                * @ngdoc method
15382                * @name $rootScope.Scope#$new
15383                * @kind function
15384                *
15385                * @description
15386                * Creates a new child {@link ng.$rootScope.Scope scope}.
15387                *
15388                * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
15389                * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
15390                *
15391                * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
15392                * desired for the scope and its child scopes to be permanently detached from the parent and
15393                * thus stop participating in model change detection and listener notification by invoking.
15394                *
15395                * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
15396                *         parent scope. The scope is isolated, as it can not see parent scope properties.
15397                *         When creating widgets, it is useful for the widget to not accidentally read parent
15398                *         state.
15399                *
15400                * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
15401                *                              of the newly created scope. Defaults to `this` scope if not provided.
15402                *                              This is used when creating a transclude scope to correctly place it
15403                *                              in the scope hierarchy while maintaining the correct prototypical
15404                *                              inheritance.
15405                *
15406                * @returns {Object} The newly created child scope.
15407                *
15408                */
15409               $new: function(isolate, parent) {
15410                 var child;
15411
15412                 parent = parent || this;
15413
15414                 if (isolate) {
15415                   child = new Scope();
15416                   child.$root = this.$root;
15417                 } else {
15418                   // Only create a child scope class if somebody asks for one,
15419                   // but cache it to allow the VM to optimize lookups.
15420                   if (!this.$$ChildScope) {
15421                     this.$$ChildScope = createChildScopeClass(this);
15422                   }
15423                   child = new this.$$ChildScope();
15424                 }
15425                 child.$parent = parent;
15426                 child.$$prevSibling = parent.$$childTail;
15427                 if (parent.$$childHead) {
15428                   parent.$$childTail.$$nextSibling = child;
15429                   parent.$$childTail = child;
15430                 } else {
15431                   parent.$$childHead = parent.$$childTail = child;
15432                 }
15433
15434                 // When the new scope is not isolated or we inherit from `this`, and
15435                 // the parent scope is destroyed, the property `$$destroyed` is inherited
15436                 // prototypically. In all other cases, this property needs to be set
15437                 // when the parent scope is destroyed.
15438                 // The listener needs to be added after the parent is set
15439                 if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
15440
15441                 return child;
15442               },
15443
15444               /**
15445                * @ngdoc method
15446                * @name $rootScope.Scope#$watch
15447                * @kind function
15448                *
15449                * @description
15450                * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
15451                *
15452                * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
15453                *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
15454                *   its value when executed multiple times with the same input because it may be executed multiple
15455                *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
15456                *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).
15457                * - The `listener` is called only when the value from the current `watchExpression` and the
15458                *   previous call to `watchExpression` are not equal (with the exception of the initial run,
15459                *   see below). Inequality is determined according to reference inequality,
15460                *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
15461                *    via the `!==` Javascript operator, unless `objectEquality == true`
15462                *   (see next point)
15463                * - When `objectEquality == true`, inequality of the `watchExpression` is determined
15464                *   according to the {@link angular.equals} function. To save the value of the object for
15465                *   later comparison, the {@link angular.copy} function is used. This therefore means that
15466                *   watching complex objects will have adverse memory and performance implications.
15467                * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
15468                *   This is achieved by rerunning the watchers until no changes are detected. The rerun
15469                *   iteration limit is 10 to prevent an infinite loop deadlock.
15470                *
15471                *
15472                * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
15473                * you can register a `watchExpression` function with no `listener`. (Be prepared for
15474                * multiple calls to your `watchExpression` because it will execute multiple times in a
15475                * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
15476                *
15477                * After a watcher is registered with the scope, the `listener` fn is called asynchronously
15478                * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
15479                * watcher. In rare cases, this is undesirable because the listener is called when the result
15480                * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
15481                * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
15482                * listener was called due to initialization.
15483                *
15484                *
15485                *
15486                * # Example
15487                * ```js
15488                    // let's assume that scope was dependency injected as the $rootScope
15489                    var scope = $rootScope;
15490                    scope.name = 'misko';
15491                    scope.counter = 0;
15492
15493                    expect(scope.counter).toEqual(0);
15494                    scope.$watch('name', function(newValue, oldValue) {
15495                      scope.counter = scope.counter + 1;
15496                    });
15497                    expect(scope.counter).toEqual(0);
15498
15499                    scope.$digest();
15500                    // the listener is always called during the first $digest loop after it was registered
15501                    expect(scope.counter).toEqual(1);
15502
15503                    scope.$digest();
15504                    // but now it will not be called unless the value changes
15505                    expect(scope.counter).toEqual(1);
15506
15507                    scope.name = 'adam';
15508                    scope.$digest();
15509                    expect(scope.counter).toEqual(2);
15510
15511
15512
15513                    // Using a function as a watchExpression
15514                    var food;
15515                    scope.foodCounter = 0;
15516                    expect(scope.foodCounter).toEqual(0);
15517                    scope.$watch(
15518                      // This function returns the value being watched. It is called for each turn of the $digest loop
15519                      function() { return food; },
15520                      // This is the change listener, called when the value returned from the above function changes
15521                      function(newValue, oldValue) {
15522                        if ( newValue !== oldValue ) {
15523                          // Only increment the counter if the value changed
15524                          scope.foodCounter = scope.foodCounter + 1;
15525                        }
15526                      }
15527                    );
15528                    // No digest has been run so the counter will be zero
15529                    expect(scope.foodCounter).toEqual(0);
15530
15531                    // Run the digest but since food has not changed count will still be zero
15532                    scope.$digest();
15533                    expect(scope.foodCounter).toEqual(0);
15534
15535                    // Update food and run digest.  Now the counter will increment
15536                    food = 'cheeseburger';
15537                    scope.$digest();
15538                    expect(scope.foodCounter).toEqual(1);
15539
15540                * ```
15541                *
15542                *
15543                *
15544                * @param {(function()|string)} watchExpression Expression that is evaluated on each
15545                *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
15546                *    a call to the `listener`.
15547                *
15548                *    - `string`: Evaluated as {@link guide/expression expression}
15549                *    - `function(scope)`: called with current `scope` as a parameter.
15550                * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
15551                *    of `watchExpression` changes.
15552                *
15553                *    - `newVal` contains the current value of the `watchExpression`
15554                *    - `oldVal` contains the previous value of the `watchExpression`
15555                *    - `scope` refers to the current scope
15556                * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
15557                *     comparing for reference equality.
15558                * @returns {function()} Returns a deregistration function for this listener.
15559                */
15560               $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
15561                 var get = $parse(watchExp);
15562
15563                 if (get.$$watchDelegate) {
15564                   return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
15565                 }
15566                 var scope = this,
15567                     array = scope.$$watchers,
15568                     watcher = {
15569                       fn: listener,
15570                       last: initWatchVal,
15571                       get: get,
15572                       exp: prettyPrintExpression || watchExp,
15573                       eq: !!objectEquality
15574                     };
15575
15576                 lastDirtyWatch = null;
15577
15578                 if (!isFunction(listener)) {
15579                   watcher.fn = noop;
15580                 }
15581
15582                 if (!array) {
15583                   array = scope.$$watchers = [];
15584                 }
15585                 // we use unshift since we use a while loop in $digest for speed.
15586                 // the while loop reads in reverse order.
15587                 array.unshift(watcher);
15588                 incrementWatchersCount(this, 1);
15589
15590                 return function deregisterWatch() {
15591                   if (arrayRemove(array, watcher) >= 0) {
15592                     incrementWatchersCount(scope, -1);
15593                   }
15594                   lastDirtyWatch = null;
15595                 };
15596               },
15597
15598               /**
15599                * @ngdoc method
15600                * @name $rootScope.Scope#$watchGroup
15601                * @kind function
15602                *
15603                * @description
15604                * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
15605                * If any one expression in the collection changes the `listener` is executed.
15606                *
15607                * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
15608                *   call to $digest() to see if any items changes.
15609                * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
15610                *
15611                * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
15612                * watched using {@link ng.$rootScope.Scope#$watch $watch()}
15613                *
15614                * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
15615                *    expression in `watchExpressions` changes
15616                *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
15617                *    those of `watchExpression`
15618                *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
15619                *    those of `watchExpression`
15620                *    The `scope` refers to the current scope.
15621                * @returns {function()} Returns a de-registration function for all listeners.
15622                */
15623               $watchGroup: function(watchExpressions, listener) {
15624                 var oldValues = new Array(watchExpressions.length);
15625                 var newValues = new Array(watchExpressions.length);
15626                 var deregisterFns = [];
15627                 var self = this;
15628                 var changeReactionScheduled = false;
15629                 var firstRun = true;
15630
15631                 if (!watchExpressions.length) {
15632                   // No expressions means we call the listener ASAP
15633                   var shouldCall = true;
15634                   self.$evalAsync(function() {
15635                     if (shouldCall) listener(newValues, newValues, self);
15636                   });
15637                   return function deregisterWatchGroup() {
15638                     shouldCall = false;
15639                   };
15640                 }
15641
15642                 if (watchExpressions.length === 1) {
15643                   // Special case size of one
15644                   return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
15645                     newValues[0] = value;
15646                     oldValues[0] = oldValue;
15647                     listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
15648                   });
15649                 }
15650
15651                 forEach(watchExpressions, function(expr, i) {
15652                   var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
15653                     newValues[i] = value;
15654                     oldValues[i] = oldValue;
15655                     if (!changeReactionScheduled) {
15656                       changeReactionScheduled = true;
15657                       self.$evalAsync(watchGroupAction);
15658                     }
15659                   });
15660                   deregisterFns.push(unwatchFn);
15661                 });
15662
15663                 function watchGroupAction() {
15664                   changeReactionScheduled = false;
15665
15666                   if (firstRun) {
15667                     firstRun = false;
15668                     listener(newValues, newValues, self);
15669                   } else {
15670                     listener(newValues, oldValues, self);
15671                   }
15672                 }
15673
15674                 return function deregisterWatchGroup() {
15675                   while (deregisterFns.length) {
15676                     deregisterFns.shift()();
15677                   }
15678                 };
15679               },
15680
15681
15682               /**
15683                * @ngdoc method
15684                * @name $rootScope.Scope#$watchCollection
15685                * @kind function
15686                *
15687                * @description
15688                * Shallow watches the properties of an object and fires whenever any of the properties change
15689                * (for arrays, this implies watching the array items; for object maps, this implies watching
15690                * the properties). If a change is detected, the `listener` callback is fired.
15691                *
15692                * - The `obj` collection is observed via standard $watch operation and is examined on every
15693                *   call to $digest() to see if any items have been added, removed, or moved.
15694                * - The `listener` is called whenever anything within the `obj` has changed. Examples include
15695                *   adding, removing, and moving items belonging to an object or array.
15696                *
15697                *
15698                * # Example
15699                * ```js
15700                   $scope.names = ['igor', 'matias', 'misko', 'james'];
15701                   $scope.dataCount = 4;
15702
15703                   $scope.$watchCollection('names', function(newNames, oldNames) {
15704                     $scope.dataCount = newNames.length;
15705                   });
15706
15707                   expect($scope.dataCount).toEqual(4);
15708                   $scope.$digest();
15709
15710                   //still at 4 ... no changes
15711                   expect($scope.dataCount).toEqual(4);
15712
15713                   $scope.names.pop();
15714                   $scope.$digest();
15715
15716                   //now there's been a change
15717                   expect($scope.dataCount).toEqual(3);
15718                * ```
15719                *
15720                *
15721                * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
15722                *    expression value should evaluate to an object or an array which is observed on each
15723                *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
15724                *    collection will trigger a call to the `listener`.
15725                *
15726                * @param {function(newCollection, oldCollection, scope)} listener a callback function called
15727                *    when a change is detected.
15728                *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
15729                *    - The `oldCollection` object is a copy of the former collection data.
15730                *      Due to performance considerations, the`oldCollection` value is computed only if the
15731                *      `listener` function declares two or more arguments.
15732                *    - The `scope` argument refers to the current scope.
15733                *
15734                * @returns {function()} Returns a de-registration function for this listener. When the
15735                *    de-registration function is executed, the internal watch operation is terminated.
15736                */
15737               $watchCollection: function(obj, listener) {
15738                 $watchCollectionInterceptor.$stateful = true;
15739
15740                 var self = this;
15741                 // the current value, updated on each dirty-check run
15742                 var newValue;
15743                 // a shallow copy of the newValue from the last dirty-check run,
15744                 // updated to match newValue during dirty-check run
15745                 var oldValue;
15746                 // a shallow copy of the newValue from when the last change happened
15747                 var veryOldValue;
15748                 // only track veryOldValue if the listener is asking for it
15749                 var trackVeryOldValue = (listener.length > 1);
15750                 var changeDetected = 0;
15751                 var changeDetector = $parse(obj, $watchCollectionInterceptor);
15752                 var internalArray = [];
15753                 var internalObject = {};
15754                 var initRun = true;
15755                 var oldLength = 0;
15756
15757                 function $watchCollectionInterceptor(_value) {
15758                   newValue = _value;
15759                   var newLength, key, bothNaN, newItem, oldItem;
15760
15761                   // If the new value is undefined, then return undefined as the watch may be a one-time watch
15762                   if (isUndefined(newValue)) return;
15763
15764                   if (!isObject(newValue)) { // if primitive
15765                     if (oldValue !== newValue) {
15766                       oldValue = newValue;
15767                       changeDetected++;
15768                     }
15769                   } else if (isArrayLike(newValue)) {
15770                     if (oldValue !== internalArray) {
15771                       // we are transitioning from something which was not an array into array.
15772                       oldValue = internalArray;
15773                       oldLength = oldValue.length = 0;
15774                       changeDetected++;
15775                     }
15776
15777                     newLength = newValue.length;
15778
15779                     if (oldLength !== newLength) {
15780                       // if lengths do not match we need to trigger change notification
15781                       changeDetected++;
15782                       oldValue.length = oldLength = newLength;
15783                     }
15784                     // copy the items to oldValue and look for changes.
15785                     for (var i = 0; i < newLength; i++) {
15786                       oldItem = oldValue[i];
15787                       newItem = newValue[i];
15788
15789                       bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15790                       if (!bothNaN && (oldItem !== newItem)) {
15791                         changeDetected++;
15792                         oldValue[i] = newItem;
15793                       }
15794                     }
15795                   } else {
15796                     if (oldValue !== internalObject) {
15797                       // we are transitioning from something which was not an object into object.
15798                       oldValue = internalObject = {};
15799                       oldLength = 0;
15800                       changeDetected++;
15801                     }
15802                     // copy the items to oldValue and look for changes.
15803                     newLength = 0;
15804                     for (key in newValue) {
15805                       if (hasOwnProperty.call(newValue, key)) {
15806                         newLength++;
15807                         newItem = newValue[key];
15808                         oldItem = oldValue[key];
15809
15810                         if (key in oldValue) {
15811                           bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15812                           if (!bothNaN && (oldItem !== newItem)) {
15813                             changeDetected++;
15814                             oldValue[key] = newItem;
15815                           }
15816                         } else {
15817                           oldLength++;
15818                           oldValue[key] = newItem;
15819                           changeDetected++;
15820                         }
15821                       }
15822                     }
15823                     if (oldLength > newLength) {
15824                       // we used to have more keys, need to find them and destroy them.
15825                       changeDetected++;
15826                       for (key in oldValue) {
15827                         if (!hasOwnProperty.call(newValue, key)) {
15828                           oldLength--;
15829                           delete oldValue[key];
15830                         }
15831                       }
15832                     }
15833                   }
15834                   return changeDetected;
15835                 }
15836
15837                 function $watchCollectionAction() {
15838                   if (initRun) {
15839                     initRun = false;
15840                     listener(newValue, newValue, self);
15841                   } else {
15842                     listener(newValue, veryOldValue, self);
15843                   }
15844
15845                   // make a copy for the next time a collection is changed
15846                   if (trackVeryOldValue) {
15847                     if (!isObject(newValue)) {
15848                       //primitive
15849                       veryOldValue = newValue;
15850                     } else if (isArrayLike(newValue)) {
15851                       veryOldValue = new Array(newValue.length);
15852                       for (var i = 0; i < newValue.length; i++) {
15853                         veryOldValue[i] = newValue[i];
15854                       }
15855                     } else { // if object
15856                       veryOldValue = {};
15857                       for (var key in newValue) {
15858                         if (hasOwnProperty.call(newValue, key)) {
15859                           veryOldValue[key] = newValue[key];
15860                         }
15861                       }
15862                     }
15863                   }
15864                 }
15865
15866                 return this.$watch(changeDetector, $watchCollectionAction);
15867               },
15868
15869               /**
15870                * @ngdoc method
15871                * @name $rootScope.Scope#$digest
15872                * @kind function
15873                *
15874                * @description
15875                * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
15876                * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
15877                * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
15878                * until no more listeners are firing. This means that it is possible to get into an infinite
15879                * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
15880                * iterations exceeds 10.
15881                *
15882                * Usually, you don't call `$digest()` directly in
15883                * {@link ng.directive:ngController controllers} or in
15884                * {@link ng.$compileProvider#directive directives}.
15885                * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
15886                * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
15887                *
15888                * If you want to be notified whenever `$digest()` is called,
15889                * you can register a `watchExpression` function with
15890                * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
15891                *
15892                * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
15893                *
15894                * # Example
15895                * ```js
15896                    var scope = ...;
15897                    scope.name = 'misko';
15898                    scope.counter = 0;
15899
15900                    expect(scope.counter).toEqual(0);
15901                    scope.$watch('name', function(newValue, oldValue) {
15902                      scope.counter = scope.counter + 1;
15903                    });
15904                    expect(scope.counter).toEqual(0);
15905
15906                    scope.$digest();
15907                    // the listener is always called during the first $digest loop after it was registered
15908                    expect(scope.counter).toEqual(1);
15909
15910                    scope.$digest();
15911                    // but now it will not be called unless the value changes
15912                    expect(scope.counter).toEqual(1);
15913
15914                    scope.name = 'adam';
15915                    scope.$digest();
15916                    expect(scope.counter).toEqual(2);
15917                * ```
15918                *
15919                */
15920               $digest: function() {
15921                 var watch, value, last,
15922                     watchers,
15923                     length,
15924                     dirty, ttl = TTL,
15925                     next, current, target = this,
15926                     watchLog = [],
15927                     logIdx, logMsg, asyncTask;
15928
15929                 beginPhase('$digest');
15930                 // Check for changes to browser url that happened in sync before the call to $digest
15931                 $browser.$$checkUrlChange();
15932
15933                 if (this === $rootScope && applyAsyncId !== null) {
15934                   // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
15935                   // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
15936                   $browser.defer.cancel(applyAsyncId);
15937                   flushApplyAsync();
15938                 }
15939
15940                 lastDirtyWatch = null;
15941
15942                 do { // "while dirty" loop
15943                   dirty = false;
15944                   current = target;
15945
15946                   while (asyncQueue.length) {
15947                     try {
15948                       asyncTask = asyncQueue.shift();
15949                       asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
15950                     } catch (e) {
15951                       $exceptionHandler(e);
15952                     }
15953                     lastDirtyWatch = null;
15954                   }
15955
15956                   traverseScopesLoop:
15957                   do { // "traverse the scopes" loop
15958                     if ((watchers = current.$$watchers)) {
15959                       // process our watches
15960                       length = watchers.length;
15961                       while (length--) {
15962                         try {
15963                           watch = watchers[length];
15964                           // Most common watches are on primitives, in which case we can short
15965                           // circuit it with === operator, only when === fails do we use .equals
15966                           if (watch) {
15967                             if ((value = watch.get(current)) !== (last = watch.last) &&
15968                                 !(watch.eq
15969                                     ? equals(value, last)
15970                                     : (typeof value === 'number' && typeof last === 'number'
15971                                        && isNaN(value) && isNaN(last)))) {
15972                               dirty = true;
15973                               lastDirtyWatch = watch;
15974                               watch.last = watch.eq ? copy(value, null) : value;
15975                               watch.fn(value, ((last === initWatchVal) ? value : last), current);
15976                               if (ttl < 5) {
15977                                 logIdx = 4 - ttl;
15978                                 if (!watchLog[logIdx]) watchLog[logIdx] = [];
15979                                 watchLog[logIdx].push({
15980                                   msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
15981                                   newVal: value,
15982                                   oldVal: last
15983                                 });
15984                               }
15985                             } else if (watch === lastDirtyWatch) {
15986                               // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
15987                               // have already been tested.
15988                               dirty = false;
15989                               break traverseScopesLoop;
15990                             }
15991                           }
15992                         } catch (e) {
15993                           $exceptionHandler(e);
15994                         }
15995                       }
15996                     }
15997
15998                     // Insanity Warning: scope depth-first traversal
15999                     // yes, this code is a bit crazy, but it works and we have tests to prove it!
16000                     // this piece should be kept in sync with the traversal in $broadcast
16001                     if (!(next = ((current.$$watchersCount && current.$$childHead) ||
16002                         (current !== target && current.$$nextSibling)))) {
16003                       while (current !== target && !(next = current.$$nextSibling)) {
16004                         current = current.$parent;
16005                       }
16006                     }
16007                   } while ((current = next));
16008
16009                   // `break traverseScopesLoop;` takes us to here
16010
16011                   if ((dirty || asyncQueue.length) && !(ttl--)) {
16012                     clearPhase();
16013                     throw $rootScopeMinErr('infdig',
16014                         '{0} $digest() iterations reached. Aborting!\n' +
16015                         'Watchers fired in the last 5 iterations: {1}',
16016                         TTL, watchLog);
16017                   }
16018
16019                 } while (dirty || asyncQueue.length);
16020
16021                 clearPhase();
16022
16023                 while (postDigestQueue.length) {
16024                   try {
16025                     postDigestQueue.shift()();
16026                   } catch (e) {
16027                     $exceptionHandler(e);
16028                   }
16029                 }
16030               },
16031
16032
16033               /**
16034                * @ngdoc event
16035                * @name $rootScope.Scope#$destroy
16036                * @eventType broadcast on scope being destroyed
16037                *
16038                * @description
16039                * Broadcasted when a scope and its children are being destroyed.
16040                *
16041                * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
16042                * clean up DOM bindings before an element is removed from the DOM.
16043                */
16044
16045               /**
16046                * @ngdoc method
16047                * @name $rootScope.Scope#$destroy
16048                * @kind function
16049                *
16050                * @description
16051                * Removes the current scope (and all of its children) from the parent scope. Removal implies
16052                * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
16053                * propagate to the current scope and its children. Removal also implies that the current
16054                * scope is eligible for garbage collection.
16055                *
16056                * The `$destroy()` is usually used by directives such as
16057                * {@link ng.directive:ngRepeat ngRepeat} for managing the
16058                * unrolling of the loop.
16059                *
16060                * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
16061                * Application code can register a `$destroy` event handler that will give it a chance to
16062                * perform any necessary cleanup.
16063                *
16064                * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
16065                * clean up DOM bindings before an element is removed from the DOM.
16066                */
16067               $destroy: function() {
16068                 // We can't destroy a scope that has been already destroyed.
16069                 if (this.$$destroyed) return;
16070                 var parent = this.$parent;
16071
16072                 this.$broadcast('$destroy');
16073                 this.$$destroyed = true;
16074
16075                 if (this === $rootScope) {
16076                   //Remove handlers attached to window when $rootScope is removed
16077                   $browser.$$applicationDestroyed();
16078                 }
16079
16080                 incrementWatchersCount(this, -this.$$watchersCount);
16081                 for (var eventName in this.$$listenerCount) {
16082                   decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
16083                 }
16084
16085                 // sever all the references to parent scopes (after this cleanup, the current scope should
16086                 // not be retained by any of our references and should be eligible for garbage collection)
16087                 if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
16088                 if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
16089                 if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
16090                 if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
16091
16092                 // Disable listeners, watchers and apply/digest methods
16093                 this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
16094                 this.$on = this.$watch = this.$watchGroup = function() { return noop; };
16095                 this.$$listeners = {};
16096
16097                 // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
16098                 this.$$nextSibling = null;
16099                 cleanUpScope(this);
16100               },
16101
16102               /**
16103                * @ngdoc method
16104                * @name $rootScope.Scope#$eval
16105                * @kind function
16106                *
16107                * @description
16108                * Executes the `expression` on the current scope and returns the result. Any exceptions in
16109                * the expression are propagated (uncaught). This is useful when evaluating Angular
16110                * expressions.
16111                *
16112                * # Example
16113                * ```js
16114                    var scope = ng.$rootScope.Scope();
16115                    scope.a = 1;
16116                    scope.b = 2;
16117
16118                    expect(scope.$eval('a+b')).toEqual(3);
16119                    expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
16120                * ```
16121                *
16122                * @param {(string|function())=} expression An angular expression to be executed.
16123                *
16124                *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
16125                *    - `function(scope)`: execute the function with the current `scope` parameter.
16126                *
16127                * @param {(object)=} locals Local variables object, useful for overriding values in scope.
16128                * @returns {*} The result of evaluating the expression.
16129                */
16130               $eval: function(expr, locals) {
16131                 return $parse(expr)(this, locals);
16132               },
16133
16134               /**
16135                * @ngdoc method
16136                * @name $rootScope.Scope#$evalAsync
16137                * @kind function
16138                *
16139                * @description
16140                * Executes the expression on the current scope at a later point in time.
16141                *
16142                * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
16143                * that:
16144                *
16145                *   - it will execute after the function that scheduled the evaluation (preferably before DOM
16146                *     rendering).
16147                *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
16148                *     `expression` execution.
16149                *
16150                * Any exceptions from the execution of the expression are forwarded to the
16151                * {@link ng.$exceptionHandler $exceptionHandler} service.
16152                *
16153                * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
16154                * will be scheduled. However, it is encouraged to always call code that changes the model
16155                * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
16156                *
16157                * @param {(string|function())=} expression An angular expression to be executed.
16158                *
16159                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16160                *    - `function(scope)`: execute the function with the current `scope` parameter.
16161                *
16162                * @param {(object)=} locals Local variables object, useful for overriding values in scope.
16163                */
16164               $evalAsync: function(expr, locals) {
16165                 // if we are outside of an $digest loop and this is the first time we are scheduling async
16166                 // task also schedule async auto-flush
16167                 if (!$rootScope.$$phase && !asyncQueue.length) {
16168                   $browser.defer(function() {
16169                     if (asyncQueue.length) {
16170                       $rootScope.$digest();
16171                     }
16172                   });
16173                 }
16174
16175                 asyncQueue.push({scope: this, expression: expr, locals: locals});
16176               },
16177
16178               $$postDigest: function(fn) {
16179                 postDigestQueue.push(fn);
16180               },
16181
16182               /**
16183                * @ngdoc method
16184                * @name $rootScope.Scope#$apply
16185                * @kind function
16186                *
16187                * @description
16188                * `$apply()` is used to execute an expression in angular from outside of the angular
16189                * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
16190                * Because we are calling into the angular framework we need to perform proper scope life
16191                * cycle of {@link ng.$exceptionHandler exception handling},
16192                * {@link ng.$rootScope.Scope#$digest executing watches}.
16193                *
16194                * ## Life cycle
16195                *
16196                * # Pseudo-Code of `$apply()`
16197                * ```js
16198                    function $apply(expr) {
16199                      try {
16200                        return $eval(expr);
16201                      } catch (e) {
16202                        $exceptionHandler(e);
16203                      } finally {
16204                        $root.$digest();
16205                      }
16206                    }
16207                * ```
16208                *
16209                *
16210                * Scope's `$apply()` method transitions through the following stages:
16211                *
16212                * 1. The {@link guide/expression expression} is executed using the
16213                *    {@link ng.$rootScope.Scope#$eval $eval()} method.
16214                * 2. Any exceptions from the execution of the expression are forwarded to the
16215                *    {@link ng.$exceptionHandler $exceptionHandler} service.
16216                * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
16217                *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
16218                *
16219                *
16220                * @param {(string|function())=} exp An angular expression to be executed.
16221                *
16222                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16223                *    - `function(scope)`: execute the function with current `scope` parameter.
16224                *
16225                * @returns {*} The result of evaluating the expression.
16226                */
16227               $apply: function(expr) {
16228                 try {
16229                   beginPhase('$apply');
16230                   try {
16231                     return this.$eval(expr);
16232                   } finally {
16233                     clearPhase();
16234                   }
16235                 } catch (e) {
16236                   $exceptionHandler(e);
16237                 } finally {
16238                   try {
16239                     $rootScope.$digest();
16240                   } catch (e) {
16241                     $exceptionHandler(e);
16242                     throw e;
16243                   }
16244                 }
16245               },
16246
16247               /**
16248                * @ngdoc method
16249                * @name $rootScope.Scope#$applyAsync
16250                * @kind function
16251                *
16252                * @description
16253                * Schedule the invocation of $apply to occur at a later time. The actual time difference
16254                * varies across browsers, but is typically around ~10 milliseconds.
16255                *
16256                * This can be used to queue up multiple expressions which need to be evaluated in the same
16257                * digest.
16258                *
16259                * @param {(string|function())=} exp An angular expression to be executed.
16260                *
16261                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16262                *    - `function(scope)`: execute the function with current `scope` parameter.
16263                */
16264               $applyAsync: function(expr) {
16265                 var scope = this;
16266                 expr && applyAsyncQueue.push($applyAsyncExpression);
16267                 scheduleApplyAsync();
16268
16269                 function $applyAsyncExpression() {
16270                   scope.$eval(expr);
16271                 }
16272               },
16273
16274               /**
16275                * @ngdoc method
16276                * @name $rootScope.Scope#$on
16277                * @kind function
16278                *
16279                * @description
16280                * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
16281                * discussion of event life cycle.
16282                *
16283                * The event listener function format is: `function(event, args...)`. The `event` object
16284                * passed into the listener has the following attributes:
16285                *
16286                *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
16287                *     `$broadcast`-ed.
16288                *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
16289                *     event propagates through the scope hierarchy, this property is set to null.
16290                *   - `name` - `{string}`: name of the event.
16291                *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
16292                *     further event propagation (available only for events that were `$emit`-ed).
16293                *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
16294                *     to true.
16295                *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
16296                *
16297                * @param {string} name Event name to listen on.
16298                * @param {function(event, ...args)} listener Function to call when the event is emitted.
16299                * @returns {function()} Returns a deregistration function for this listener.
16300                */
16301               $on: function(name, listener) {
16302                 var namedListeners = this.$$listeners[name];
16303                 if (!namedListeners) {
16304                   this.$$listeners[name] = namedListeners = [];
16305                 }
16306                 namedListeners.push(listener);
16307
16308                 var current = this;
16309                 do {
16310                   if (!current.$$listenerCount[name]) {
16311                     current.$$listenerCount[name] = 0;
16312                   }
16313                   current.$$listenerCount[name]++;
16314                 } while ((current = current.$parent));
16315
16316                 var self = this;
16317                 return function() {
16318                   var indexOfListener = namedListeners.indexOf(listener);
16319                   if (indexOfListener !== -1) {
16320                     namedListeners[indexOfListener] = null;
16321                     decrementListenerCount(self, 1, name);
16322                   }
16323                 };
16324               },
16325
16326
16327               /**
16328                * @ngdoc method
16329                * @name $rootScope.Scope#$emit
16330                * @kind function
16331                *
16332                * @description
16333                * Dispatches an event `name` upwards through the scope hierarchy notifying the
16334                * registered {@link ng.$rootScope.Scope#$on} listeners.
16335                *
16336                * The event life cycle starts at the scope on which `$emit` was called. All
16337                * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
16338                * notified. Afterwards, the event traverses upwards toward the root scope and calls all
16339                * registered listeners along the way. The event will stop propagating if one of the listeners
16340                * cancels it.
16341                *
16342                * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16343                * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16344                *
16345                * @param {string} name Event name to emit.
16346                * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16347                * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
16348                */
16349               $emit: function(name, args) {
16350                 var empty = [],
16351                     namedListeners,
16352                     scope = this,
16353                     stopPropagation = false,
16354                     event = {
16355                       name: name,
16356                       targetScope: scope,
16357                       stopPropagation: function() {stopPropagation = true;},
16358                       preventDefault: function() {
16359                         event.defaultPrevented = true;
16360                       },
16361                       defaultPrevented: false
16362                     },
16363                     listenerArgs = concat([event], arguments, 1),
16364                     i, length;
16365
16366                 do {
16367                   namedListeners = scope.$$listeners[name] || empty;
16368                   event.currentScope = scope;
16369                   for (i = 0, length = namedListeners.length; i < length; i++) {
16370
16371                     // if listeners were deregistered, defragment the array
16372                     if (!namedListeners[i]) {
16373                       namedListeners.splice(i, 1);
16374                       i--;
16375                       length--;
16376                       continue;
16377                     }
16378                     try {
16379                       //allow all listeners attached to the current scope to run
16380                       namedListeners[i].apply(null, listenerArgs);
16381                     } catch (e) {
16382                       $exceptionHandler(e);
16383                     }
16384                   }
16385                   //if any listener on the current scope stops propagation, prevent bubbling
16386                   if (stopPropagation) {
16387                     event.currentScope = null;
16388                     return event;
16389                   }
16390                   //traverse upwards
16391                   scope = scope.$parent;
16392                 } while (scope);
16393
16394                 event.currentScope = null;
16395
16396                 return event;
16397               },
16398
16399
16400               /**
16401                * @ngdoc method
16402                * @name $rootScope.Scope#$broadcast
16403                * @kind function
16404                *
16405                * @description
16406                * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
16407                * registered {@link ng.$rootScope.Scope#$on} listeners.
16408                *
16409                * The event life cycle starts at the scope on which `$broadcast` was called. All
16410                * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
16411                * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
16412                * scope and calls all registered listeners along the way. The event cannot be canceled.
16413                *
16414                * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16415                * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16416                *
16417                * @param {string} name Event name to broadcast.
16418                * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16419                * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
16420                */
16421               $broadcast: function(name, args) {
16422                 var target = this,
16423                     current = target,
16424                     next = target,
16425                     event = {
16426                       name: name,
16427                       targetScope: target,
16428                       preventDefault: function() {
16429                         event.defaultPrevented = true;
16430                       },
16431                       defaultPrevented: false
16432                     };
16433
16434                 if (!target.$$listenerCount[name]) return event;
16435
16436                 var listenerArgs = concat([event], arguments, 1),
16437                     listeners, i, length;
16438
16439                 //down while you can, then up and next sibling or up and next sibling until back at root
16440                 while ((current = next)) {
16441                   event.currentScope = current;
16442                   listeners = current.$$listeners[name] || [];
16443                   for (i = 0, length = listeners.length; i < length; i++) {
16444                     // if listeners were deregistered, defragment the array
16445                     if (!listeners[i]) {
16446                       listeners.splice(i, 1);
16447                       i--;
16448                       length--;
16449                       continue;
16450                     }
16451
16452                     try {
16453                       listeners[i].apply(null, listenerArgs);
16454                     } catch (e) {
16455                       $exceptionHandler(e);
16456                     }
16457                   }
16458
16459                   // Insanity Warning: scope depth-first traversal
16460                   // yes, this code is a bit crazy, but it works and we have tests to prove it!
16461                   // this piece should be kept in sync with the traversal in $digest
16462                   // (though it differs due to having the extra check for $$listenerCount)
16463                   if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
16464                       (current !== target && current.$$nextSibling)))) {
16465                     while (current !== target && !(next = current.$$nextSibling)) {
16466                       current = current.$parent;
16467                     }
16468                   }
16469                 }
16470
16471                 event.currentScope = null;
16472                 return event;
16473               }
16474             };
16475
16476             var $rootScope = new Scope();
16477
16478             //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
16479             var asyncQueue = $rootScope.$$asyncQueue = [];
16480             var postDigestQueue = $rootScope.$$postDigestQueue = [];
16481             var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
16482
16483             return $rootScope;
16484
16485
16486             function beginPhase(phase) {
16487               if ($rootScope.$$phase) {
16488                 throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
16489               }
16490
16491               $rootScope.$$phase = phase;
16492             }
16493
16494             function clearPhase() {
16495               $rootScope.$$phase = null;
16496             }
16497
16498             function incrementWatchersCount(current, count) {
16499               do {
16500                 current.$$watchersCount += count;
16501               } while ((current = current.$parent));
16502             }
16503
16504             function decrementListenerCount(current, count, name) {
16505               do {
16506                 current.$$listenerCount[name] -= count;
16507
16508                 if (current.$$listenerCount[name] === 0) {
16509                   delete current.$$listenerCount[name];
16510                 }
16511               } while ((current = current.$parent));
16512             }
16513
16514             /**
16515              * function used as an initial value for watchers.
16516              * because it's unique we can easily tell it apart from other values
16517              */
16518             function initWatchVal() {}
16519
16520             function flushApplyAsync() {
16521               while (applyAsyncQueue.length) {
16522                 try {
16523                   applyAsyncQueue.shift()();
16524                 } catch (e) {
16525                   $exceptionHandler(e);
16526                 }
16527               }
16528               applyAsyncId = null;
16529             }
16530
16531             function scheduleApplyAsync() {
16532               if (applyAsyncId === null) {
16533                 applyAsyncId = $browser.defer(function() {
16534                   $rootScope.$apply(flushApplyAsync);
16535                 });
16536               }
16537             }
16538           }];
16539         }
16540
16541         /**
16542          * @description
16543          * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
16544          */
16545         function $$SanitizeUriProvider() {
16546           var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
16547             imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
16548
16549           /**
16550            * @description
16551            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16552            * urls during a[href] sanitization.
16553            *
16554            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16555            *
16556            * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
16557            * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
16558            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16559            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16560            *
16561            * @param {RegExp=} regexp New regexp to whitelist urls with.
16562            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16563            *    chaining otherwise.
16564            */
16565           this.aHrefSanitizationWhitelist = function(regexp) {
16566             if (isDefined(regexp)) {
16567               aHrefSanitizationWhitelist = regexp;
16568               return this;
16569             }
16570             return aHrefSanitizationWhitelist;
16571           };
16572
16573
16574           /**
16575            * @description
16576            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16577            * urls during img[src] sanitization.
16578            *
16579            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16580            *
16581            * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
16582            * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
16583            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16584            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16585            *
16586            * @param {RegExp=} regexp New regexp to whitelist urls with.
16587            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16588            *    chaining otherwise.
16589            */
16590           this.imgSrcSanitizationWhitelist = function(regexp) {
16591             if (isDefined(regexp)) {
16592               imgSrcSanitizationWhitelist = regexp;
16593               return this;
16594             }
16595             return imgSrcSanitizationWhitelist;
16596           };
16597
16598           this.$get = function() {
16599             return function sanitizeUri(uri, isImage) {
16600               var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
16601               var normalizedVal;
16602               normalizedVal = urlResolve(uri).href;
16603               if (normalizedVal !== '' && !normalizedVal.match(regex)) {
16604                 return 'unsafe:' + normalizedVal;
16605               }
16606               return uri;
16607             };
16608           };
16609         }
16610
16611         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16612          *     Any commits to this file should be reviewed with security in mind.  *
16613          *   Changes to this file can potentially create security vulnerabilities. *
16614          *          An approval from 2 Core members with history of modifying      *
16615          *                         this file is required.                          *
16616          *                                                                         *
16617          *  Does the change somehow allow for arbitrary javascript to be executed? *
16618          *    Or allows for someone to change the prototype of built-in objects?   *
16619          *     Or gives undesired access to variables likes document or window?    *
16620          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16621
16622         var $sceMinErr = minErr('$sce');
16623
16624         var SCE_CONTEXTS = {
16625           HTML: 'html',
16626           CSS: 'css',
16627           URL: 'url',
16628           // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
16629           // url.  (e.g. ng-include, script src, templateUrl)
16630           RESOURCE_URL: 'resourceUrl',
16631           JS: 'js'
16632         };
16633
16634         // Helper functions follow.
16635
16636         function adjustMatcher(matcher) {
16637           if (matcher === 'self') {
16638             return matcher;
16639           } else if (isString(matcher)) {
16640             // Strings match exactly except for 2 wildcards - '*' and '**'.
16641             // '*' matches any character except those from the set ':/.?&'.
16642             // '**' matches any character (like .* in a RegExp).
16643             // More than 2 *'s raises an error as it's ill defined.
16644             if (matcher.indexOf('***') > -1) {
16645               throw $sceMinErr('iwcard',
16646                   'Illegal sequence *** in string matcher.  String: {0}', matcher);
16647             }
16648             matcher = escapeForRegexp(matcher).
16649                           replace('\\*\\*', '.*').
16650                           replace('\\*', '[^:/.?&;]*');
16651             return new RegExp('^' + matcher + '$');
16652           } else if (isRegExp(matcher)) {
16653             // The only other type of matcher allowed is a Regexp.
16654             // Match entire URL / disallow partial matches.
16655             // Flags are reset (i.e. no global, ignoreCase or multiline)
16656             return new RegExp('^' + matcher.source + '$');
16657           } else {
16658             throw $sceMinErr('imatcher',
16659                 'Matchers may only be "self", string patterns or RegExp objects');
16660           }
16661         }
16662
16663
16664         function adjustMatchers(matchers) {
16665           var adjustedMatchers = [];
16666           if (isDefined(matchers)) {
16667             forEach(matchers, function(matcher) {
16668               adjustedMatchers.push(adjustMatcher(matcher));
16669             });
16670           }
16671           return adjustedMatchers;
16672         }
16673
16674
16675         /**
16676          * @ngdoc service
16677          * @name $sceDelegate
16678          * @kind function
16679          *
16680          * @description
16681          *
16682          * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
16683          * Contextual Escaping (SCE)} services to AngularJS.
16684          *
16685          * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
16686          * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
16687          * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
16688          * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
16689          * work because `$sce` delegates to `$sceDelegate` for these operations.
16690          *
16691          * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
16692          *
16693          * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
16694          * can override it completely to change the behavior of `$sce`, the common case would
16695          * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
16696          * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
16697          * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
16698          * $sceDelegateProvider.resourceUrlWhitelist} and {@link
16699          * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16700          */
16701
16702         /**
16703          * @ngdoc provider
16704          * @name $sceDelegateProvider
16705          * @description
16706          *
16707          * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
16708          * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
16709          * that the URLs used for sourcing Angular templates are safe.  Refer {@link
16710          * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
16711          * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16712          *
16713          * For the general details about this service in Angular, read the main page for {@link ng.$sce
16714          * Strict Contextual Escaping (SCE)}.
16715          *
16716          * **Example**:  Consider the following case. <a name="example"></a>
16717          *
16718          * - your app is hosted at url `http://myapp.example.com/`
16719          * - but some of your templates are hosted on other domains you control such as
16720          *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
16721          * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
16722          *
16723          * Here is what a secure configuration for this scenario might look like:
16724          *
16725          * ```
16726          *  angular.module('myApp', []).config(function($sceDelegateProvider) {
16727          *    $sceDelegateProvider.resourceUrlWhitelist([
16728          *      // Allow same origin resource loads.
16729          *      'self',
16730          *      // Allow loading from our assets domain.  Notice the difference between * and **.
16731          *      'http://srv*.assets.example.com/**'
16732          *    ]);
16733          *
16734          *    // The blacklist overrides the whitelist so the open redirect here is blocked.
16735          *    $sceDelegateProvider.resourceUrlBlacklist([
16736          *      'http://myapp.example.com/clickThru**'
16737          *    ]);
16738          *  });
16739          * ```
16740          */
16741
16742         function $SceDelegateProvider() {
16743           this.SCE_CONTEXTS = SCE_CONTEXTS;
16744
16745           // Resource URLs can also be trusted by policy.
16746           var resourceUrlWhitelist = ['self'],
16747               resourceUrlBlacklist = [];
16748
16749           /**
16750            * @ngdoc method
16751            * @name $sceDelegateProvider#resourceUrlWhitelist
16752            * @kind function
16753            *
16754            * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
16755            *     provided.  This must be an array or null.  A snapshot of this array is used so further
16756            *     changes to the array are ignored.
16757            *
16758            *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16759            *     allowed in this array.
16760            *
16761            *     Note: **an empty whitelist array will block all URLs**!
16762            *
16763            * @return {Array} the currently set whitelist array.
16764            *
16765            * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
16766            * same origin resource requests.
16767            *
16768            * @description
16769            * Sets/Gets the whitelist of trusted resource URLs.
16770            */
16771           this.resourceUrlWhitelist = function(value) {
16772             if (arguments.length) {
16773               resourceUrlWhitelist = adjustMatchers(value);
16774             }
16775             return resourceUrlWhitelist;
16776           };
16777
16778           /**
16779            * @ngdoc method
16780            * @name $sceDelegateProvider#resourceUrlBlacklist
16781            * @kind function
16782            *
16783            * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
16784            *     provided.  This must be an array or null.  A snapshot of this array is used so further
16785            *     changes to the array are ignored.
16786            *
16787            *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16788            *     allowed in this array.
16789            *
16790            *     The typical usage for the blacklist is to **block
16791            *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
16792            *     these would otherwise be trusted but actually return content from the redirected domain.
16793            *
16794            *     Finally, **the blacklist overrides the whitelist** and has the final say.
16795            *
16796            * @return {Array} the currently set blacklist array.
16797            *
16798            * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
16799            * is no blacklist.)
16800            *
16801            * @description
16802            * Sets/Gets the blacklist of trusted resource URLs.
16803            */
16804
16805           this.resourceUrlBlacklist = function(value) {
16806             if (arguments.length) {
16807               resourceUrlBlacklist = adjustMatchers(value);
16808             }
16809             return resourceUrlBlacklist;
16810           };
16811
16812           this.$get = ['$injector', function($injector) {
16813
16814             var htmlSanitizer = function htmlSanitizer(html) {
16815               throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16816             };
16817
16818             if ($injector.has('$sanitize')) {
16819               htmlSanitizer = $injector.get('$sanitize');
16820             }
16821
16822
16823             function matchUrl(matcher, parsedUrl) {
16824               if (matcher === 'self') {
16825                 return urlIsSameOrigin(parsedUrl);
16826               } else {
16827                 // definitely a regex.  See adjustMatchers()
16828                 return !!matcher.exec(parsedUrl.href);
16829               }
16830             }
16831
16832             function isResourceUrlAllowedByPolicy(url) {
16833               var parsedUrl = urlResolve(url.toString());
16834               var i, n, allowed = false;
16835               // Ensure that at least one item from the whitelist allows this url.
16836               for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
16837                 if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
16838                   allowed = true;
16839                   break;
16840                 }
16841               }
16842               if (allowed) {
16843                 // Ensure that no item from the blacklist blocked this url.
16844                 for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
16845                   if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
16846                     allowed = false;
16847                     break;
16848                   }
16849                 }
16850               }
16851               return allowed;
16852             }
16853
16854             function generateHolderType(Base) {
16855               var holderType = function TrustedValueHolderType(trustedValue) {
16856                 this.$$unwrapTrustedValue = function() {
16857                   return trustedValue;
16858                 };
16859               };
16860               if (Base) {
16861                 holderType.prototype = new Base();
16862               }
16863               holderType.prototype.valueOf = function sceValueOf() {
16864                 return this.$$unwrapTrustedValue();
16865               };
16866               holderType.prototype.toString = function sceToString() {
16867                 return this.$$unwrapTrustedValue().toString();
16868               };
16869               return holderType;
16870             }
16871
16872             var trustedValueHolderBase = generateHolderType(),
16873                 byType = {};
16874
16875             byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
16876             byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
16877             byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
16878             byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
16879             byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
16880
16881             /**
16882              * @ngdoc method
16883              * @name $sceDelegate#trustAs
16884              *
16885              * @description
16886              * Returns an object that is trusted by angular for use in specified strict
16887              * contextual escaping contexts (such as ng-bind-html, ng-include, any src
16888              * attribute interpolation, any dom event binding attribute interpolation
16889              * such as for onclick,  etc.) that uses the provided value.
16890              * See {@link ng.$sce $sce} for enabling strict contextual escaping.
16891              *
16892              * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
16893              *   resourceUrl, html, js and css.
16894              * @param {*} value The value that that should be considered trusted/safe.
16895              * @returns {*} A value that can be used to stand in for the provided `value` in places
16896              * where Angular expects a $sce.trustAs() return value.
16897              */
16898             function trustAs(type, trustedValue) {
16899               var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16900               if (!Constructor) {
16901                 throw $sceMinErr('icontext',
16902                     'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
16903                     type, trustedValue);
16904               }
16905               if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
16906                 return trustedValue;
16907               }
16908               // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
16909               // mutable objects, we ensure here that the value passed in is actually a string.
16910               if (typeof trustedValue !== 'string') {
16911                 throw $sceMinErr('itype',
16912                     'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
16913                     type);
16914               }
16915               return new Constructor(trustedValue);
16916             }
16917
16918             /**
16919              * @ngdoc method
16920              * @name $sceDelegate#valueOf
16921              *
16922              * @description
16923              * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
16924              * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
16925              * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
16926              *
16927              * If the passed parameter is not a value that had been returned by {@link
16928              * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
16929              *
16930              * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
16931              *      call or anything else.
16932              * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
16933              *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
16934              *     `value` unchanged.
16935              */
16936             function valueOf(maybeTrusted) {
16937               if (maybeTrusted instanceof trustedValueHolderBase) {
16938                 return maybeTrusted.$$unwrapTrustedValue();
16939               } else {
16940                 return maybeTrusted;
16941               }
16942             }
16943
16944             /**
16945              * @ngdoc method
16946              * @name $sceDelegate#getTrusted
16947              *
16948              * @description
16949              * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
16950              * returns the originally supplied value if the queried context type is a supertype of the
16951              * created type.  If this condition isn't satisfied, throws an exception.
16952              *
16953              * @param {string} type The kind of context in which this value is to be used.
16954              * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
16955              *     `$sceDelegate.trustAs`} call.
16956              * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
16957              *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
16958              */
16959             function getTrusted(type, maybeTrusted) {
16960               if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
16961                 return maybeTrusted;
16962               }
16963               var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16964               if (constructor && maybeTrusted instanceof constructor) {
16965                 return maybeTrusted.$$unwrapTrustedValue();
16966               }
16967               // If we get here, then we may only take one of two actions.
16968               // 1. sanitize the value for the requested type, or
16969               // 2. throw an exception.
16970               if (type === SCE_CONTEXTS.RESOURCE_URL) {
16971                 if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
16972                   return maybeTrusted;
16973                 } else {
16974                   throw $sceMinErr('insecurl',
16975                       'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
16976                       maybeTrusted.toString());
16977                 }
16978               } else if (type === SCE_CONTEXTS.HTML) {
16979                 return htmlSanitizer(maybeTrusted);
16980               }
16981               throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16982             }
16983
16984             return { trustAs: trustAs,
16985                      getTrusted: getTrusted,
16986                      valueOf: valueOf };
16987           }];
16988         }
16989
16990
16991         /**
16992          * @ngdoc provider
16993          * @name $sceProvider
16994          * @description
16995          *
16996          * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
16997          * -   enable/disable Strict Contextual Escaping (SCE) in a module
16998          * -   override the default implementation with a custom delegate
16999          *
17000          * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
17001          */
17002
17003         /* jshint maxlen: false*/
17004
17005         /**
17006          * @ngdoc service
17007          * @name $sce
17008          * @kind function
17009          *
17010          * @description
17011          *
17012          * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
17013          *
17014          * # Strict Contextual Escaping
17015          *
17016          * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
17017          * contexts to result in a value that is marked as safe to use for that context.  One example of
17018          * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
17019          * to these contexts as privileged or SCE contexts.
17020          *
17021          * As of version 1.2, Angular ships with SCE enabled by default.
17022          *
17023          * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
17024          * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
17025          * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
17026          * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
17027          * to the top of your HTML document.
17028          *
17029          * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
17030          * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
17031          *
17032          * Here's an example of a binding in a privileged context:
17033          *
17034          * ```
17035          * <input ng-model="userHtml" aria-label="User input">
17036          * <div ng-bind-html="userHtml"></div>
17037          * ```
17038          *
17039          * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
17040          * disabled, this application allows the user to render arbitrary HTML into the DIV.
17041          * In a more realistic example, one may be rendering user comments, blog articles, etc. via
17042          * bindings.  (HTML is just one example of a context where rendering user controlled input creates
17043          * security vulnerabilities.)
17044          *
17045          * For the case of HTML, you might use a library, either on the client side, or on the server side,
17046          * to sanitize unsafe HTML before binding to the value and rendering it in the document.
17047          *
17048          * How would you ensure that every place that used these types of bindings was bound to a value that
17049          * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
17050          * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
17051          * properties/fields and forgot to update the binding to the sanitized value?
17052          *
17053          * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
17054          * determine that something explicitly says it's safe to use a value for binding in that
17055          * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
17056          * for those values that you can easily tell are safe - because they were received from your server,
17057          * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
17058          * allowing only the files in a specific directory to do this.  Ensuring that the internal API
17059          * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
17060          *
17061          * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
17062          * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
17063          * obtain values that will be accepted by SCE / privileged contexts.
17064          *
17065          *
17066          * ## How does it work?
17067          *
17068          * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
17069          * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
17070          * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
17071          * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
17072          *
17073          * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
17074          * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
17075          * simplified):
17076          *
17077          * ```
17078          * var ngBindHtmlDirective = ['$sce', function($sce) {
17079          *   return function(scope, element, attr) {
17080          *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
17081          *       element.html(value || '');
17082          *     });
17083          *   };
17084          * }];
17085          * ```
17086          *
17087          * ## Impact on loading templates
17088          *
17089          * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
17090          * `templateUrl`'s specified by {@link guide/directive directives}.
17091          *
17092          * By default, Angular only loads templates from the same domain and protocol as the application
17093          * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
17094          * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
17095          * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
17096          * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
17097          *
17098          * *Please note*:
17099          * The browser's
17100          * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
17101          * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
17102          * policy apply in addition to this and may further restrict whether the template is successfully
17103          * loaded.  This means that without the right CORS policy, loading templates from a different domain
17104          * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
17105          * browsers.
17106          *
17107          * ## This feels like too much overhead
17108          *
17109          * It's important to remember that SCE only applies to interpolation expressions.
17110          *
17111          * If your expressions are constant literals, they're automatically trusted and you don't need to
17112          * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
17113          * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
17114          *
17115          * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
17116          * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
17117          *
17118          * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
17119          * templates in `ng-include` from your application's domain without having to even know about SCE.
17120          * It blocks loading templates from other domains or loading templates over http from an https
17121          * served document.  You can change these by setting your own custom {@link
17122          * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
17123          * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
17124          *
17125          * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
17126          * application that's secure and can be audited to verify that with much more ease than bolting
17127          * security onto an application later.
17128          *
17129          * <a name="contexts"></a>
17130          * ## What trusted context types are supported?
17131          *
17132          * | Context             | Notes          |
17133          * |---------------------|----------------|
17134          * | `$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. |
17135          * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
17136          * | `$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. |
17137          * | `$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. |
17138          * | `$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. |
17139          *
17140          * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
17141          *
17142          *  Each element in these arrays must be one of the following:
17143          *
17144          *  - **'self'**
17145          *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
17146          *      domain** as the application document using the **same protocol**.
17147          *  - **String** (except the special value `'self'`)
17148          *    - The string is matched against the full *normalized / absolute URL* of the resource
17149          *      being tested (substring matches are not good enough.)
17150          *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
17151          *      match themselves.
17152          *    - `*`: matches zero or more occurrences of any character other than one of the following 6
17153          *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
17154          *      in a whitelist.
17155          *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
17156          *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
17157          *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
17158          *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
17159          *      http://foo.example.com/templates/**).
17160          *  - **RegExp** (*see caveat below*)
17161          *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
17162          *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
17163          *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
17164          *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
17165          *      small number of cases.  A `.` character in the regex used when matching the scheme or a
17166          *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
17167          *      is highly recommended to use the string patterns and only fall back to regular expressions
17168          *      as a last resort.
17169          *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
17170          *      matched against the **entire** *normalized / absolute URL* of the resource being tested
17171          *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
17172          *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
17173          *    - If you are generating your JavaScript from some other templating engine (not
17174          *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
17175          *      remember to escape your regular expression (and be aware that you might need more than
17176          *      one level of escaping depending on your templating engine and the way you interpolated
17177          *      the value.)  Do make use of your platform's escaping mechanism as it might be good
17178          *      enough before coding your own.  E.g. Ruby has
17179          *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
17180          *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
17181          *      Javascript lacks a similar built in function for escaping.  Take a look at Google
17182          *      Closure library's [goog.string.regExpEscape(s)](
17183          *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
17184          *
17185          * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
17186          *
17187          * ## Show me an example using SCE.
17188          *
17189          * <example module="mySceApp" deps="angular-sanitize.js">
17190          * <file name="index.html">
17191          *   <div ng-controller="AppController as myCtrl">
17192          *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
17193          *     <b>User comments</b><br>
17194          *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
17195          *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
17196          *     exploit.
17197          *     <div class="well">
17198          *       <div ng-repeat="userComment in myCtrl.userComments">
17199          *         <b>{{userComment.name}}</b>:
17200          *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
17201          *         <br>
17202          *       </div>
17203          *     </div>
17204          *   </div>
17205          * </file>
17206          *
17207          * <file name="script.js">
17208          *   angular.module('mySceApp', ['ngSanitize'])
17209          *     .controller('AppController', ['$http', '$templateCache', '$sce',
17210          *       function($http, $templateCache, $sce) {
17211          *         var self = this;
17212          *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
17213          *           self.userComments = userComments;
17214          *         });
17215          *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
17216          *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
17217          *             'sanitization.&quot;">Hover over this text.</span>');
17218          *       }]);
17219          * </file>
17220          *
17221          * <file name="test_data.json">
17222          * [
17223          *   { "name": "Alice",
17224          *     "htmlComment":
17225          *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
17226          *   },
17227          *   { "name": "Bob",
17228          *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
17229          *   }
17230          * ]
17231          * </file>
17232          *
17233          * <file name="protractor.js" type="protractor">
17234          *   describe('SCE doc demo', function() {
17235          *     it('should sanitize untrusted values', function() {
17236          *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
17237          *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
17238          *     });
17239          *
17240          *     it('should NOT sanitize explicitly trusted values', function() {
17241          *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
17242          *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
17243          *           'sanitization.&quot;">Hover over this text.</span>');
17244          *     });
17245          *   });
17246          * </file>
17247          * </example>
17248          *
17249          *
17250          *
17251          * ## Can I disable SCE completely?
17252          *
17253          * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
17254          * for little coding overhead.  It will be much harder to take an SCE disabled application and
17255          * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
17256          * for cases where you have a lot of existing code that was written before SCE was introduced and
17257          * you're migrating them a module at a time.
17258          *
17259          * That said, here's how you can completely disable SCE:
17260          *
17261          * ```
17262          * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
17263          *   // Completely disable SCE.  For demonstration purposes only!
17264          *   // Do not use in new projects.
17265          *   $sceProvider.enabled(false);
17266          * });
17267          * ```
17268          *
17269          */
17270         /* jshint maxlen: 100 */
17271
17272         function $SceProvider() {
17273           var enabled = true;
17274
17275           /**
17276            * @ngdoc method
17277            * @name $sceProvider#enabled
17278            * @kind function
17279            *
17280            * @param {boolean=} value If provided, then enables/disables SCE.
17281            * @return {boolean} true if SCE is enabled, false otherwise.
17282            *
17283            * @description
17284            * Enables/disables SCE and returns the current value.
17285            */
17286           this.enabled = function(value) {
17287             if (arguments.length) {
17288               enabled = !!value;
17289             }
17290             return enabled;
17291           };
17292
17293
17294           /* Design notes on the default implementation for SCE.
17295            *
17296            * The API contract for the SCE delegate
17297            * -------------------------------------
17298            * The SCE delegate object must provide the following 3 methods:
17299            *
17300            * - trustAs(contextEnum, value)
17301            *     This method is used to tell the SCE service that the provided value is OK to use in the
17302            *     contexts specified by contextEnum.  It must return an object that will be accepted by
17303            *     getTrusted() for a compatible contextEnum and return this value.
17304            *
17305            * - valueOf(value)
17306            *     For values that were not produced by trustAs(), return them as is.  For values that were
17307            *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
17308            *     trustAs is wrapping the given values into some type, this operation unwraps it when given
17309            *     such a value.
17310            *
17311            * - getTrusted(contextEnum, value)
17312            *     This function should return the a value that is safe to use in the context specified by
17313            *     contextEnum or throw and exception otherwise.
17314            *
17315            * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
17316            * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
17317            * instance, an implementation could maintain a registry of all trusted objects by context.  In
17318            * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
17319            * return the same object passed in if it was found in the registry under a compatible context or
17320            * throw an exception otherwise.  An implementation might only wrap values some of the time based
17321            * on some criteria.  getTrusted() might return a value and not throw an exception for special
17322            * constants or objects even if not wrapped.  All such implementations fulfill this contract.
17323            *
17324            *
17325            * A note on the inheritance model for SCE contexts
17326            * ------------------------------------------------
17327            * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
17328            * is purely an implementation details.
17329            *
17330            * The contract is simply this:
17331            *
17332            *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
17333            *     will also succeed.
17334            *
17335            * Inheritance happens to capture this in a natural way.  In some future, we
17336            * may not use inheritance anymore.  That is OK because no code outside of
17337            * sce.js and sceSpecs.js would need to be aware of this detail.
17338            */
17339
17340           this.$get = ['$parse', '$sceDelegate', function(
17341                         $parse,   $sceDelegate) {
17342             // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
17343             // the "expression(javascript expression)" syntax which is insecure.
17344             if (enabled && msie < 8) {
17345               throw $sceMinErr('iequirks',
17346                 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
17347                 'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
17348                 'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
17349             }
17350
17351             var sce = shallowCopy(SCE_CONTEXTS);
17352
17353             /**
17354              * @ngdoc method
17355              * @name $sce#isEnabled
17356              * @kind function
17357              *
17358              * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
17359              * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
17360              *
17361              * @description
17362              * Returns a boolean indicating if SCE is enabled.
17363              */
17364             sce.isEnabled = function() {
17365               return enabled;
17366             };
17367             sce.trustAs = $sceDelegate.trustAs;
17368             sce.getTrusted = $sceDelegate.getTrusted;
17369             sce.valueOf = $sceDelegate.valueOf;
17370
17371             if (!enabled) {
17372               sce.trustAs = sce.getTrusted = function(type, value) { return value; };
17373               sce.valueOf = identity;
17374             }
17375
17376             /**
17377              * @ngdoc method
17378              * @name $sce#parseAs
17379              *
17380              * @description
17381              * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
17382              * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
17383              * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
17384              * *result*)}
17385              *
17386              * @param {string} type The kind of SCE context in which this result will be used.
17387              * @param {string} expression String expression to compile.
17388              * @returns {function(context, locals)} a function which represents the compiled expression:
17389              *
17390              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17391              *      are evaluated against (typically a scope object).
17392              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17393              *      `context`.
17394              */
17395             sce.parseAs = function sceParseAs(type, expr) {
17396               var parsed = $parse(expr);
17397               if (parsed.literal && parsed.constant) {
17398                 return parsed;
17399               } else {
17400                 return $parse(expr, function(value) {
17401                   return sce.getTrusted(type, value);
17402                 });
17403               }
17404             };
17405
17406             /**
17407              * @ngdoc method
17408              * @name $sce#trustAs
17409              *
17410              * @description
17411              * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
17412              * returns an object that is trusted by angular for use in specified strict contextual
17413              * escaping contexts (such as ng-bind-html, ng-include, any src attribute
17414              * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
17415              * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
17416              * escaping.
17417              *
17418              * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
17419              *   resourceUrl, html, js and css.
17420              * @param {*} value The value that that should be considered trusted/safe.
17421              * @returns {*} A value that can be used to stand in for the provided `value` in places
17422              * where Angular expects a $sce.trustAs() return value.
17423              */
17424
17425             /**
17426              * @ngdoc method
17427              * @name $sce#trustAsHtml
17428              *
17429              * @description
17430              * Shorthand method.  `$sce.trustAsHtml(value)` →
17431              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
17432              *
17433              * @param {*} value The value to trustAs.
17434              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
17435              *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
17436              *     only accept expressions that are either literal constants or are the
17437              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17438              */
17439
17440             /**
17441              * @ngdoc method
17442              * @name $sce#trustAsUrl
17443              *
17444              * @description
17445              * Shorthand method.  `$sce.trustAsUrl(value)` →
17446              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
17447              *
17448              * @param {*} value The value to trustAs.
17449              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
17450              *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
17451              *     only accept expressions that are either literal constants or are the
17452              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17453              */
17454
17455             /**
17456              * @ngdoc method
17457              * @name $sce#trustAsResourceUrl
17458              *
17459              * @description
17460              * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
17461              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
17462              *
17463              * @param {*} value The value to trustAs.
17464              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
17465              *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
17466              *     only accept expressions that are either literal constants or are the return
17467              *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
17468              */
17469
17470             /**
17471              * @ngdoc method
17472              * @name $sce#trustAsJs
17473              *
17474              * @description
17475              * Shorthand method.  `$sce.trustAsJs(value)` →
17476              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
17477              *
17478              * @param {*} value The value to trustAs.
17479              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
17480              *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
17481              *     only accept expressions that are either literal constants or are the
17482              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17483              */
17484
17485             /**
17486              * @ngdoc method
17487              * @name $sce#getTrusted
17488              *
17489              * @description
17490              * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
17491              * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
17492              * originally supplied value if the queried context type is a supertype of the created type.
17493              * If this condition isn't satisfied, throws an exception.
17494              *
17495              * @param {string} type The kind of context in which this value is to be used.
17496              * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
17497              *                         call.
17498              * @returns {*} The value the was originally provided to
17499              *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
17500              *              Otherwise, throws an exception.
17501              */
17502
17503             /**
17504              * @ngdoc method
17505              * @name $sce#getTrustedHtml
17506              *
17507              * @description
17508              * Shorthand method.  `$sce.getTrustedHtml(value)` →
17509              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
17510              *
17511              * @param {*} value The value to pass to `$sce.getTrusted`.
17512              * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
17513              */
17514
17515             /**
17516              * @ngdoc method
17517              * @name $sce#getTrustedCss
17518              *
17519              * @description
17520              * Shorthand method.  `$sce.getTrustedCss(value)` →
17521              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
17522              *
17523              * @param {*} value The value to pass to `$sce.getTrusted`.
17524              * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
17525              */
17526
17527             /**
17528              * @ngdoc method
17529              * @name $sce#getTrustedUrl
17530              *
17531              * @description
17532              * Shorthand method.  `$sce.getTrustedUrl(value)` →
17533              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
17534              *
17535              * @param {*} value The value to pass to `$sce.getTrusted`.
17536              * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
17537              */
17538
17539             /**
17540              * @ngdoc method
17541              * @name $sce#getTrustedResourceUrl
17542              *
17543              * @description
17544              * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
17545              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
17546              *
17547              * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
17548              * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
17549              */
17550
17551             /**
17552              * @ngdoc method
17553              * @name $sce#getTrustedJs
17554              *
17555              * @description
17556              * Shorthand method.  `$sce.getTrustedJs(value)` →
17557              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
17558              *
17559              * @param {*} value The value to pass to `$sce.getTrusted`.
17560              * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
17561              */
17562
17563             /**
17564              * @ngdoc method
17565              * @name $sce#parseAsHtml
17566              *
17567              * @description
17568              * Shorthand method.  `$sce.parseAsHtml(expression string)` →
17569              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
17570              *
17571              * @param {string} expression String expression to compile.
17572              * @returns {function(context, locals)} a function which represents the compiled expression:
17573              *
17574              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17575              *      are evaluated against (typically a scope object).
17576              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17577              *      `context`.
17578              */
17579
17580             /**
17581              * @ngdoc method
17582              * @name $sce#parseAsCss
17583              *
17584              * @description
17585              * Shorthand method.  `$sce.parseAsCss(value)` →
17586              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
17587              *
17588              * @param {string} expression String expression to compile.
17589              * @returns {function(context, locals)} a function which represents the compiled expression:
17590              *
17591              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17592              *      are evaluated against (typically a scope object).
17593              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17594              *      `context`.
17595              */
17596
17597             /**
17598              * @ngdoc method
17599              * @name $sce#parseAsUrl
17600              *
17601              * @description
17602              * Shorthand method.  `$sce.parseAsUrl(value)` →
17603              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
17604              *
17605              * @param {string} expression String expression to compile.
17606              * @returns {function(context, locals)} a function which represents the compiled expression:
17607              *
17608              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17609              *      are evaluated against (typically a scope object).
17610              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17611              *      `context`.
17612              */
17613
17614             /**
17615              * @ngdoc method
17616              * @name $sce#parseAsResourceUrl
17617              *
17618              * @description
17619              * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
17620              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
17621              *
17622              * @param {string} expression String expression to compile.
17623              * @returns {function(context, locals)} a function which represents the compiled expression:
17624              *
17625              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17626              *      are evaluated against (typically a scope object).
17627              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17628              *      `context`.
17629              */
17630
17631             /**
17632              * @ngdoc method
17633              * @name $sce#parseAsJs
17634              *
17635              * @description
17636              * Shorthand method.  `$sce.parseAsJs(value)` →
17637              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
17638              *
17639              * @param {string} expression String expression to compile.
17640              * @returns {function(context, locals)} a function which represents the compiled expression:
17641              *
17642              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17643              *      are evaluated against (typically a scope object).
17644              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17645              *      `context`.
17646              */
17647
17648             // Shorthand delegations.
17649             var parse = sce.parseAs,
17650                 getTrusted = sce.getTrusted,
17651                 trustAs = sce.trustAs;
17652
17653             forEach(SCE_CONTEXTS, function(enumValue, name) {
17654               var lName = lowercase(name);
17655               sce[camelCase("parse_as_" + lName)] = function(expr) {
17656                 return parse(enumValue, expr);
17657               };
17658               sce[camelCase("get_trusted_" + lName)] = function(value) {
17659                 return getTrusted(enumValue, value);
17660               };
17661               sce[camelCase("trust_as_" + lName)] = function(value) {
17662                 return trustAs(enumValue, value);
17663               };
17664             });
17665
17666             return sce;
17667           }];
17668         }
17669
17670         /**
17671          * !!! This is an undocumented "private" service !!!
17672          *
17673          * @name $sniffer
17674          * @requires $window
17675          * @requires $document
17676          *
17677          * @property {boolean} history Does the browser support html5 history api ?
17678          * @property {boolean} transitions Does the browser support CSS transition events ?
17679          * @property {boolean} animations Does the browser support CSS animation events ?
17680          *
17681          * @description
17682          * This is very simple implementation of testing browser's features.
17683          */
17684         function $SnifferProvider() {
17685           this.$get = ['$window', '$document', function($window, $document) {
17686             var eventSupport = {},
17687                 android =
17688                   toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
17689                 boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
17690                 document = $document[0] || {},
17691                 vendorPrefix,
17692                 vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
17693                 bodyStyle = document.body && document.body.style,
17694                 transitions = false,
17695                 animations = false,
17696                 match;
17697
17698             if (bodyStyle) {
17699               for (var prop in bodyStyle) {
17700                 if (match = vendorRegex.exec(prop)) {
17701                   vendorPrefix = match[0];
17702                   vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
17703                   break;
17704                 }
17705               }
17706
17707               if (!vendorPrefix) {
17708                 vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
17709               }
17710
17711               transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
17712               animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
17713
17714               if (android && (!transitions ||  !animations)) {
17715                 transitions = isString(bodyStyle.webkitTransition);
17716                 animations = isString(bodyStyle.webkitAnimation);
17717               }
17718             }
17719
17720
17721             return {
17722               // Android has history.pushState, but it does not update location correctly
17723               // so let's not use the history API at all.
17724               // http://code.google.com/p/android/issues/detail?id=17471
17725               // https://github.com/angular/angular.js/issues/904
17726
17727               // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
17728               // so let's not use the history API also
17729               // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
17730               // jshint -W018
17731               history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
17732               // jshint +W018
17733               hasEvent: function(event) {
17734                 // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
17735                 // it. In particular the event is not fired when backspace or delete key are pressed or
17736                 // when cut operation is performed.
17737                 // IE10+ implements 'input' event but it erroneously fires under various situations,
17738                 // e.g. when placeholder changes, or a form is focused.
17739                 if (event === 'input' && msie <= 11) return false;
17740
17741                 if (isUndefined(eventSupport[event])) {
17742                   var divElm = document.createElement('div');
17743                   eventSupport[event] = 'on' + event in divElm;
17744                 }
17745
17746                 return eventSupport[event];
17747               },
17748               csp: csp(),
17749               vendorPrefix: vendorPrefix,
17750               transitions: transitions,
17751               animations: animations,
17752               android: android
17753             };
17754           }];
17755         }
17756
17757         var $compileMinErr = minErr('$compile');
17758
17759         /**
17760          * @ngdoc service
17761          * @name $templateRequest
17762          *
17763          * @description
17764          * The `$templateRequest` service runs security checks then downloads the provided template using
17765          * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
17766          * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
17767          * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
17768          * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
17769          * when `tpl` is of type string and `$templateCache` has the matching entry.
17770          *
17771          * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
17772          * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
17773          *
17774          * @return {Promise} a promise for the HTTP response data of the given URL.
17775          *
17776          * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
17777          */
17778         function $TemplateRequestProvider() {
17779           this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
17780             function handleRequestFn(tpl, ignoreRequestError) {
17781               handleRequestFn.totalPendingRequests++;
17782
17783               // We consider the template cache holds only trusted templates, so
17784               // there's no need to go through whitelisting again for keys that already
17785               // are included in there. This also makes Angular accept any script
17786               // directive, no matter its name. However, we still need to unwrap trusted
17787               // types.
17788               if (!isString(tpl) || !$templateCache.get(tpl)) {
17789                 tpl = $sce.getTrustedResourceUrl(tpl);
17790               }
17791
17792               var transformResponse = $http.defaults && $http.defaults.transformResponse;
17793
17794               if (isArray(transformResponse)) {
17795                 transformResponse = transformResponse.filter(function(transformer) {
17796                   return transformer !== defaultHttpResponseTransform;
17797                 });
17798               } else if (transformResponse === defaultHttpResponseTransform) {
17799                 transformResponse = null;
17800               }
17801
17802               var httpOptions = {
17803                 cache: $templateCache,
17804                 transformResponse: transformResponse
17805               };
17806
17807               return $http.get(tpl, httpOptions)
17808                 ['finally'](function() {
17809                   handleRequestFn.totalPendingRequests--;
17810                 })
17811                 .then(function(response) {
17812                   $templateCache.put(tpl, response.data);
17813                   return response.data;
17814                 }, handleError);
17815
17816               function handleError(resp) {
17817                 if (!ignoreRequestError) {
17818                   throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
17819                     tpl, resp.status, resp.statusText);
17820                 }
17821                 return $q.reject(resp);
17822               }
17823             }
17824
17825             handleRequestFn.totalPendingRequests = 0;
17826
17827             return handleRequestFn;
17828           }];
17829         }
17830
17831         function $$TestabilityProvider() {
17832           this.$get = ['$rootScope', '$browser', '$location',
17833                function($rootScope,   $browser,   $location) {
17834
17835             /**
17836              * @name $testability
17837              *
17838              * @description
17839              * The private $$testability service provides a collection of methods for use when debugging
17840              * or by automated test and debugging tools.
17841              */
17842             var testability = {};
17843
17844             /**
17845              * @name $$testability#findBindings
17846              *
17847              * @description
17848              * Returns an array of elements that are bound (via ng-bind or {{}})
17849              * to expressions matching the input.
17850              *
17851              * @param {Element} element The element root to search from.
17852              * @param {string} expression The binding expression to match.
17853              * @param {boolean} opt_exactMatch If true, only returns exact matches
17854              *     for the expression. Filters and whitespace are ignored.
17855              */
17856             testability.findBindings = function(element, expression, opt_exactMatch) {
17857               var bindings = element.getElementsByClassName('ng-binding');
17858               var matches = [];
17859               forEach(bindings, function(binding) {
17860                 var dataBinding = angular.element(binding).data('$binding');
17861                 if (dataBinding) {
17862                   forEach(dataBinding, function(bindingName) {
17863                     if (opt_exactMatch) {
17864                       var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
17865                       if (matcher.test(bindingName)) {
17866                         matches.push(binding);
17867                       }
17868                     } else {
17869                       if (bindingName.indexOf(expression) != -1) {
17870                         matches.push(binding);
17871                       }
17872                     }
17873                   });
17874                 }
17875               });
17876               return matches;
17877             };
17878
17879             /**
17880              * @name $$testability#findModels
17881              *
17882              * @description
17883              * Returns an array of elements that are two-way found via ng-model to
17884              * expressions matching the input.
17885              *
17886              * @param {Element} element The element root to search from.
17887              * @param {string} expression The model expression to match.
17888              * @param {boolean} opt_exactMatch If true, only returns exact matches
17889              *     for the expression.
17890              */
17891             testability.findModels = function(element, expression, opt_exactMatch) {
17892               var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
17893               for (var p = 0; p < prefixes.length; ++p) {
17894                 var attributeEquals = opt_exactMatch ? '=' : '*=';
17895                 var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
17896                 var elements = element.querySelectorAll(selector);
17897                 if (elements.length) {
17898                   return elements;
17899                 }
17900               }
17901             };
17902
17903             /**
17904              * @name $$testability#getLocation
17905              *
17906              * @description
17907              * Shortcut for getting the location in a browser agnostic way. Returns
17908              *     the path, search, and hash. (e.g. /path?a=b#hash)
17909              */
17910             testability.getLocation = function() {
17911               return $location.url();
17912             };
17913
17914             /**
17915              * @name $$testability#setLocation
17916              *
17917              * @description
17918              * Shortcut for navigating to a location without doing a full page reload.
17919              *
17920              * @param {string} url The location url (path, search and hash,
17921              *     e.g. /path?a=b#hash) to go to.
17922              */
17923             testability.setLocation = function(url) {
17924               if (url !== $location.url()) {
17925                 $location.url(url);
17926                 $rootScope.$digest();
17927               }
17928             };
17929
17930             /**
17931              * @name $$testability#whenStable
17932              *
17933              * @description
17934              * Calls the callback when $timeout and $http requests are completed.
17935              *
17936              * @param {function} callback
17937              */
17938             testability.whenStable = function(callback) {
17939               $browser.notifyWhenNoOutstandingRequests(callback);
17940             };
17941
17942             return testability;
17943           }];
17944         }
17945
17946         function $TimeoutProvider() {
17947           this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
17948                function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
17949
17950             var deferreds = {};
17951
17952
17953              /**
17954               * @ngdoc service
17955               * @name $timeout
17956               *
17957               * @description
17958               * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
17959               * block and delegates any exceptions to
17960               * {@link ng.$exceptionHandler $exceptionHandler} service.
17961               *
17962               * The return value of calling `$timeout` is a promise, which will be resolved when
17963               * the delay has passed and the timeout function, if provided, is executed.
17964               *
17965               * To cancel a timeout request, call `$timeout.cancel(promise)`.
17966               *
17967               * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
17968               * synchronously flush the queue of deferred functions.
17969               *
17970               * If you only want a promise that will be resolved after some specified delay
17971               * then you can call `$timeout` without the `fn` function.
17972               *
17973               * @param {function()=} fn A function, whose execution should be delayed.
17974               * @param {number=} [delay=0] Delay in milliseconds.
17975               * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
17976               *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
17977               * @param {...*=} Pass additional parameters to the executed function.
17978               * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
17979               *   promise will be resolved with is the return value of the `fn` function.
17980               *
17981               */
17982             function timeout(fn, delay, invokeApply) {
17983               if (!isFunction(fn)) {
17984                 invokeApply = delay;
17985                 delay = fn;
17986                 fn = noop;
17987               }
17988
17989               var args = sliceArgs(arguments, 3),
17990                   skipApply = (isDefined(invokeApply) && !invokeApply),
17991                   deferred = (skipApply ? $$q : $q).defer(),
17992                   promise = deferred.promise,
17993                   timeoutId;
17994
17995               timeoutId = $browser.defer(function() {
17996                 try {
17997                   deferred.resolve(fn.apply(null, args));
17998                 } catch (e) {
17999                   deferred.reject(e);
18000                   $exceptionHandler(e);
18001                 }
18002                 finally {
18003                   delete deferreds[promise.$$timeoutId];
18004                 }
18005
18006                 if (!skipApply) $rootScope.$apply();
18007               }, delay);
18008
18009               promise.$$timeoutId = timeoutId;
18010               deferreds[timeoutId] = deferred;
18011
18012               return promise;
18013             }
18014
18015
18016              /**
18017               * @ngdoc method
18018               * @name $timeout#cancel
18019               *
18020               * @description
18021               * Cancels a task associated with the `promise`. As a result of this, the promise will be
18022               * resolved with a rejection.
18023               *
18024               * @param {Promise=} promise Promise returned by the `$timeout` function.
18025               * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
18026               *   canceled.
18027               */
18028             timeout.cancel = function(promise) {
18029               if (promise && promise.$$timeoutId in deferreds) {
18030                 deferreds[promise.$$timeoutId].reject('canceled');
18031                 delete deferreds[promise.$$timeoutId];
18032                 return $browser.defer.cancel(promise.$$timeoutId);
18033               }
18034               return false;
18035             };
18036
18037             return timeout;
18038           }];
18039         }
18040
18041         // NOTE:  The usage of window and document instead of $window and $document here is
18042         // deliberate.  This service depends on the specific behavior of anchor nodes created by the
18043         // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
18044         // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
18045         // doesn't know about mocked locations and resolves URLs to the real document - which is
18046         // exactly the behavior needed here.  There is little value is mocking these out for this
18047         // service.
18048         var urlParsingNode = document.createElement("a");
18049         var originUrl = urlResolve(window.location.href);
18050
18051
18052         /**
18053          *
18054          * Implementation Notes for non-IE browsers
18055          * ----------------------------------------
18056          * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
18057          * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
18058          * URL will be resolved into an absolute URL in the context of the application document.
18059          * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
18060          * properties are all populated to reflect the normalized URL.  This approach has wide
18061          * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
18062          * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
18063          *
18064          * Implementation Notes for IE
18065          * ---------------------------
18066          * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
18067          * browsers.  However, the parsed components will not be set if the URL assigned did not specify
18068          * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
18069          * work around that by performing the parsing in a 2nd step by taking a previously normalized
18070          * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
18071          * properties such as protocol, hostname, port, etc.
18072          *
18073          * References:
18074          *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
18075          *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
18076          *   http://url.spec.whatwg.org/#urlutils
18077          *   https://github.com/angular/angular.js/pull/2902
18078          *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
18079          *
18080          * @kind function
18081          * @param {string} url The URL to be parsed.
18082          * @description Normalizes and parses a URL.
18083          * @returns {object} Returns the normalized URL as a dictionary.
18084          *
18085          *   | member name   | Description    |
18086          *   |---------------|----------------|
18087          *   | href          | A normalized version of the provided URL if it was not an absolute URL |
18088          *   | protocol      | The protocol including the trailing colon                              |
18089          *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
18090          *   | search        | The search params, minus the question mark                             |
18091          *   | hash          | The hash string, minus the hash symbol
18092          *   | hostname      | The hostname
18093          *   | port          | The port, without ":"
18094          *   | pathname      | The pathname, beginning with "/"
18095          *
18096          */
18097         function urlResolve(url) {
18098           var href = url;
18099
18100           if (msie) {
18101             // Normalize before parse.  Refer Implementation Notes on why this is
18102             // done in two steps on IE.
18103             urlParsingNode.setAttribute("href", href);
18104             href = urlParsingNode.href;
18105           }
18106
18107           urlParsingNode.setAttribute('href', href);
18108
18109           // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
18110           return {
18111             href: urlParsingNode.href,
18112             protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
18113             host: urlParsingNode.host,
18114             search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
18115             hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
18116             hostname: urlParsingNode.hostname,
18117             port: urlParsingNode.port,
18118             pathname: (urlParsingNode.pathname.charAt(0) === '/')
18119               ? urlParsingNode.pathname
18120               : '/' + urlParsingNode.pathname
18121           };
18122         }
18123
18124         /**
18125          * Parse a request URL and determine whether this is a same-origin request as the application document.
18126          *
18127          * @param {string|object} requestUrl The url of the request as a string that will be resolved
18128          * or a parsed URL object.
18129          * @returns {boolean} Whether the request is for the same origin as the application document.
18130          */
18131         function urlIsSameOrigin(requestUrl) {
18132           var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
18133           return (parsed.protocol === originUrl.protocol &&
18134                   parsed.host === originUrl.host);
18135         }
18136
18137         /**
18138          * @ngdoc service
18139          * @name $window
18140          *
18141          * @description
18142          * A reference to the browser's `window` object. While `window`
18143          * is globally available in JavaScript, it causes testability problems, because
18144          * it is a global variable. In angular we always refer to it through the
18145          * `$window` service, so it may be overridden, removed or mocked for testing.
18146          *
18147          * Expressions, like the one defined for the `ngClick` directive in the example
18148          * below, are evaluated with respect to the current scope.  Therefore, there is
18149          * no risk of inadvertently coding in a dependency on a global value in such an
18150          * expression.
18151          *
18152          * @example
18153            <example module="windowExample">
18154              <file name="index.html">
18155                <script>
18156                  angular.module('windowExample', [])
18157                    .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
18158                      $scope.greeting = 'Hello, World!';
18159                      $scope.doGreeting = function(greeting) {
18160                        $window.alert(greeting);
18161                      };
18162                    }]);
18163                </script>
18164                <div ng-controller="ExampleController">
18165                  <input type="text" ng-model="greeting" aria-label="greeting" />
18166                  <button ng-click="doGreeting(greeting)">ALERT</button>
18167                </div>
18168              </file>
18169              <file name="protractor.js" type="protractor">
18170               it('should display the greeting in the input box', function() {
18171                element(by.model('greeting')).sendKeys('Hello, E2E Tests');
18172                // If we click the button it will block the test runner
18173                // element(':button').click();
18174               });
18175              </file>
18176            </example>
18177          */
18178         function $WindowProvider() {
18179           this.$get = valueFn(window);
18180         }
18181
18182         /**
18183          * @name $$cookieReader
18184          * @requires $document
18185          *
18186          * @description
18187          * This is a private service for reading cookies used by $http and ngCookies
18188          *
18189          * @return {Object} a key/value map of the current cookies
18190          */
18191         function $$CookieReader($document) {
18192           var rawDocument = $document[0] || {};
18193           var lastCookies = {};
18194           var lastCookieString = '';
18195
18196           function safeDecodeURIComponent(str) {
18197             try {
18198               return decodeURIComponent(str);
18199             } catch (e) {
18200               return str;
18201             }
18202           }
18203
18204           return function() {
18205             var cookieArray, cookie, i, index, name;
18206             var currentCookieString = rawDocument.cookie || '';
18207
18208             if (currentCookieString !== lastCookieString) {
18209               lastCookieString = currentCookieString;
18210               cookieArray = lastCookieString.split('; ');
18211               lastCookies = {};
18212
18213               for (i = 0; i < cookieArray.length; i++) {
18214                 cookie = cookieArray[i];
18215                 index = cookie.indexOf('=');
18216                 if (index > 0) { //ignore nameless cookies
18217                   name = safeDecodeURIComponent(cookie.substring(0, index));
18218                   // the first value that is seen for a cookie is the most
18219                   // specific one.  values for the same cookie name that
18220                   // follow are for less specific paths.
18221                   if (isUndefined(lastCookies[name])) {
18222                     lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
18223                   }
18224                 }
18225               }
18226             }
18227             return lastCookies;
18228           };
18229         }
18230
18231         $$CookieReader.$inject = ['$document'];
18232
18233         function $$CookieReaderProvider() {
18234           this.$get = $$CookieReader;
18235         }
18236
18237         /* global currencyFilter: true,
18238          dateFilter: true,
18239          filterFilter: true,
18240          jsonFilter: true,
18241          limitToFilter: true,
18242          lowercaseFilter: true,
18243          numberFilter: true,
18244          orderByFilter: true,
18245          uppercaseFilter: true,
18246          */
18247
18248         /**
18249          * @ngdoc provider
18250          * @name $filterProvider
18251          * @description
18252          *
18253          * Filters are just functions which transform input to an output. However filters need to be
18254          * Dependency Injected. To achieve this a filter definition consists of a factory function which is
18255          * annotated with dependencies and is responsible for creating a filter function.
18256          *
18257          * <div class="alert alert-warning">
18258          * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
18259          * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
18260          * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
18261          * (`myapp_subsection_filterx`).
18262          * </div>
18263          *
18264          * ```js
18265          *   // Filter registration
18266          *   function MyModule($provide, $filterProvider) {
18267          *     // create a service to demonstrate injection (not always needed)
18268          *     $provide.value('greet', function(name){
18269          *       return 'Hello ' + name + '!';
18270          *     });
18271          *
18272          *     // register a filter factory which uses the
18273          *     // greet service to demonstrate DI.
18274          *     $filterProvider.register('greet', function(greet){
18275          *       // return the filter function which uses the greet service
18276          *       // to generate salutation
18277          *       return function(text) {
18278          *         // filters need to be forgiving so check input validity
18279          *         return text && greet(text) || text;
18280          *       };
18281          *     });
18282          *   }
18283          * ```
18284          *
18285          * The filter function is registered with the `$injector` under the filter name suffix with
18286          * `Filter`.
18287          *
18288          * ```js
18289          *   it('should be the same instance', inject(
18290          *     function($filterProvider) {
18291          *       $filterProvider.register('reverse', function(){
18292          *         return ...;
18293          *       });
18294          *     },
18295          *     function($filter, reverseFilter) {
18296          *       expect($filter('reverse')).toBe(reverseFilter);
18297          *     });
18298          * ```
18299          *
18300          *
18301          * For more information about how angular filters work, and how to create your own filters, see
18302          * {@link guide/filter Filters} in the Angular Developer Guide.
18303          */
18304
18305         /**
18306          * @ngdoc service
18307          * @name $filter
18308          * @kind function
18309          * @description
18310          * Filters are used for formatting data displayed to the user.
18311          *
18312          * The general syntax in templates is as follows:
18313          *
18314          *         {{ expression [| filter_name[:parameter_value] ... ] }}
18315          *
18316          * @param {String} name Name of the filter function to retrieve
18317          * @return {Function} the filter function
18318          * @example
18319            <example name="$filter" module="filterExample">
18320              <file name="index.html">
18321                <div ng-controller="MainCtrl">
18322                 <h3>{{ originalText }}</h3>
18323                 <h3>{{ filteredText }}</h3>
18324                </div>
18325              </file>
18326
18327              <file name="script.js">
18328               angular.module('filterExample', [])
18329               .controller('MainCtrl', function($scope, $filter) {
18330                 $scope.originalText = 'hello';
18331                 $scope.filteredText = $filter('uppercase')($scope.originalText);
18332               });
18333              </file>
18334            </example>
18335           */
18336         $FilterProvider.$inject = ['$provide'];
18337         function $FilterProvider($provide) {
18338           var suffix = 'Filter';
18339
18340           /**
18341            * @ngdoc method
18342            * @name $filterProvider#register
18343            * @param {string|Object} name Name of the filter function, or an object map of filters where
18344            *    the keys are the filter names and the values are the filter factories.
18345            *
18346            *    <div class="alert alert-warning">
18347            *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
18348            *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
18349            *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
18350            *    (`myapp_subsection_filterx`).
18351            *    </div>
18352             * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
18353            * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
18354            *    of the registered filter instances.
18355            */
18356           function register(name, factory) {
18357             if (isObject(name)) {
18358               var filters = {};
18359               forEach(name, function(filter, key) {
18360                 filters[key] = register(key, filter);
18361               });
18362               return filters;
18363             } else {
18364               return $provide.factory(name + suffix, factory);
18365             }
18366           }
18367           this.register = register;
18368
18369           this.$get = ['$injector', function($injector) {
18370             return function(name) {
18371               return $injector.get(name + suffix);
18372             };
18373           }];
18374
18375           ////////////////////////////////////////
18376
18377           /* global
18378             currencyFilter: false,
18379             dateFilter: false,
18380             filterFilter: false,
18381             jsonFilter: false,
18382             limitToFilter: false,
18383             lowercaseFilter: false,
18384             numberFilter: false,
18385             orderByFilter: false,
18386             uppercaseFilter: false,
18387           */
18388
18389           register('currency', currencyFilter);
18390           register('date', dateFilter);
18391           register('filter', filterFilter);
18392           register('json', jsonFilter);
18393           register('limitTo', limitToFilter);
18394           register('lowercase', lowercaseFilter);
18395           register('number', numberFilter);
18396           register('orderBy', orderByFilter);
18397           register('uppercase', uppercaseFilter);
18398         }
18399
18400         /**
18401          * @ngdoc filter
18402          * @name filter
18403          * @kind function
18404          *
18405          * @description
18406          * Selects a subset of items from `array` and returns it as a new array.
18407          *
18408          * @param {Array} array The source array.
18409          * @param {string|Object|function()} expression The predicate to be used for selecting items from
18410          *   `array`.
18411          *
18412          *   Can be one of:
18413          *
18414          *   - `string`: The string is used for matching against the contents of the `array`. All strings or
18415          *     objects with string properties in `array` that match this string will be returned. This also
18416          *     applies to nested object properties.
18417          *     The predicate can be negated by prefixing the string with `!`.
18418          *
18419          *   - `Object`: A pattern object can be used to filter specific properties on objects contained
18420          *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
18421          *     which have property `name` containing "M" and property `phone` containing "1". A special
18422          *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
18423          *     property of the object or its nested object properties. That's equivalent to the simple
18424          *     substring match with a `string` as described above. The predicate can be negated by prefixing
18425          *     the string with `!`.
18426          *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
18427          *     not containing "M".
18428          *
18429          *     Note that a named property will match properties on the same level only, while the special
18430          *     `$` property will match properties on the same level or deeper. E.g. an array item like
18431          *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
18432          *     **will** be matched by `{$: 'John'}`.
18433          *
18434          *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
18435          *     The function is called for each element of the array, with the element, its index, and
18436          *     the entire array itself as arguments.
18437          *
18438          *     The final result is an array of those elements that the predicate returned true for.
18439          *
18440          * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
18441          *     determining if the expected value (from the filter expression) and actual value (from
18442          *     the object in the array) should be considered a match.
18443          *
18444          *   Can be one of:
18445          *
18446          *   - `function(actual, expected)`:
18447          *     The function will be given the object value and the predicate value to compare and
18448          *     should return true if both values should be considered equal.
18449          *
18450          *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
18451          *     This is essentially strict comparison of expected and actual.
18452          *
18453          *   - `false|undefined`: A short hand for a function which will look for a substring match in case
18454          *     insensitive way.
18455          *
18456          *     Primitive values are converted to strings. Objects are not compared against primitives,
18457          *     unless they have a custom `toString` method (e.g. `Date` objects).
18458          *
18459          * @example
18460            <example>
18461              <file name="index.html">
18462                <div ng-init="friends = [{name:'John', phone:'555-1276'},
18463                                         {name:'Mary', phone:'800-BIG-MARY'},
18464                                         {name:'Mike', phone:'555-4321'},
18465                                         {name:'Adam', phone:'555-5678'},
18466                                         {name:'Julie', phone:'555-8765'},
18467                                         {name:'Juliette', phone:'555-5678'}]"></div>
18468
18469                <label>Search: <input ng-model="searchText"></label>
18470                <table id="searchTextResults">
18471                  <tr><th>Name</th><th>Phone</th></tr>
18472                  <tr ng-repeat="friend in friends | filter:searchText">
18473                    <td>{{friend.name}}</td>
18474                    <td>{{friend.phone}}</td>
18475                  </tr>
18476                </table>
18477                <hr>
18478                <label>Any: <input ng-model="search.$"></label> <br>
18479                <label>Name only <input ng-model="search.name"></label><br>
18480                <label>Phone only <input ng-model="search.phone"></label><br>
18481                <label>Equality <input type="checkbox" ng-model="strict"></label><br>
18482                <table id="searchObjResults">
18483                  <tr><th>Name</th><th>Phone</th></tr>
18484                  <tr ng-repeat="friendObj in friends | filter:search:strict">
18485                    <td>{{friendObj.name}}</td>
18486                    <td>{{friendObj.phone}}</td>
18487                  </tr>
18488                </table>
18489              </file>
18490              <file name="protractor.js" type="protractor">
18491                var expectFriendNames = function(expectedNames, key) {
18492                  element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
18493                    arr.forEach(function(wd, i) {
18494                      expect(wd.getText()).toMatch(expectedNames[i]);
18495                    });
18496                  });
18497                };
18498
18499                it('should search across all fields when filtering with a string', function() {
18500                  var searchText = element(by.model('searchText'));
18501                  searchText.clear();
18502                  searchText.sendKeys('m');
18503                  expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
18504
18505                  searchText.clear();
18506                  searchText.sendKeys('76');
18507                  expectFriendNames(['John', 'Julie'], 'friend');
18508                });
18509
18510                it('should search in specific fields when filtering with a predicate object', function() {
18511                  var searchAny = element(by.model('search.$'));
18512                  searchAny.clear();
18513                  searchAny.sendKeys('i');
18514                  expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
18515                });
18516                it('should use a equal comparison when comparator is true', function() {
18517                  var searchName = element(by.model('search.name'));
18518                  var strict = element(by.model('strict'));
18519                  searchName.clear();
18520                  searchName.sendKeys('Julie');
18521                  strict.click();
18522                  expectFriendNames(['Julie'], 'friendObj');
18523                });
18524              </file>
18525            </example>
18526          */
18527         function filterFilter() {
18528           return function(array, expression, comparator) {
18529             if (!isArrayLike(array)) {
18530               if (array == null) {
18531                 return array;
18532               } else {
18533                 throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
18534               }
18535             }
18536
18537             var expressionType = getTypeForFilter(expression);
18538             var predicateFn;
18539             var matchAgainstAnyProp;
18540
18541             switch (expressionType) {
18542               case 'function':
18543                 predicateFn = expression;
18544                 break;
18545               case 'boolean':
18546               case 'null':
18547               case 'number':
18548               case 'string':
18549                 matchAgainstAnyProp = true;
18550                 //jshint -W086
18551               case 'object':
18552                 //jshint +W086
18553                 predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
18554                 break;
18555               default:
18556                 return array;
18557             }
18558
18559             return Array.prototype.filter.call(array, predicateFn);
18560           };
18561         }
18562
18563         // Helper functions for `filterFilter`
18564         function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
18565           var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
18566           var predicateFn;
18567
18568           if (comparator === true) {
18569             comparator = equals;
18570           } else if (!isFunction(comparator)) {
18571             comparator = function(actual, expected) {
18572               if (isUndefined(actual)) {
18573                 // No substring matching against `undefined`
18574                 return false;
18575               }
18576               if ((actual === null) || (expected === null)) {
18577                 // No substring matching against `null`; only match against `null`
18578                 return actual === expected;
18579               }
18580               if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
18581                 // Should not compare primitives against objects, unless they have custom `toString` method
18582                 return false;
18583               }
18584
18585               actual = lowercase('' + actual);
18586               expected = lowercase('' + expected);
18587               return actual.indexOf(expected) !== -1;
18588             };
18589           }
18590
18591           predicateFn = function(item) {
18592             if (shouldMatchPrimitives && !isObject(item)) {
18593               return deepCompare(item, expression.$, comparator, false);
18594             }
18595             return deepCompare(item, expression, comparator, matchAgainstAnyProp);
18596           };
18597
18598           return predicateFn;
18599         }
18600
18601         function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
18602           var actualType = getTypeForFilter(actual);
18603           var expectedType = getTypeForFilter(expected);
18604
18605           if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
18606             return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
18607           } else if (isArray(actual)) {
18608             // In case `actual` is an array, consider it a match
18609             // if ANY of it's items matches `expected`
18610             return actual.some(function(item) {
18611               return deepCompare(item, expected, comparator, matchAgainstAnyProp);
18612             });
18613           }
18614
18615           switch (actualType) {
18616             case 'object':
18617               var key;
18618               if (matchAgainstAnyProp) {
18619                 for (key in actual) {
18620                   if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
18621                     return true;
18622                   }
18623                 }
18624                 return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
18625               } else if (expectedType === 'object') {
18626                 for (key in expected) {
18627                   var expectedVal = expected[key];
18628                   if (isFunction(expectedVal) || isUndefined(expectedVal)) {
18629                     continue;
18630                   }
18631
18632                   var matchAnyProperty = key === '$';
18633                   var actualVal = matchAnyProperty ? actual : actual[key];
18634                   if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
18635                     return false;
18636                   }
18637                 }
18638                 return true;
18639               } else {
18640                 return comparator(actual, expected);
18641               }
18642               break;
18643             case 'function':
18644               return false;
18645             default:
18646               return comparator(actual, expected);
18647           }
18648         }
18649
18650         // Used for easily differentiating between `null` and actual `object`
18651         function getTypeForFilter(val) {
18652           return (val === null) ? 'null' : typeof val;
18653         }
18654
18655         /**
18656          * @ngdoc filter
18657          * @name currency
18658          * @kind function
18659          *
18660          * @description
18661          * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
18662          * symbol for current locale is used.
18663          *
18664          * @param {number} amount Input to filter.
18665          * @param {string=} symbol Currency symbol or identifier to be displayed.
18666          * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
18667          * @returns {string} Formatted number.
18668          *
18669          *
18670          * @example
18671            <example module="currencyExample">
18672              <file name="index.html">
18673                <script>
18674                  angular.module('currencyExample', [])
18675                    .controller('ExampleController', ['$scope', function($scope) {
18676                      $scope.amount = 1234.56;
18677                    }]);
18678                </script>
18679                <div ng-controller="ExampleController">
18680                  <input type="number" ng-model="amount" aria-label="amount"> <br>
18681                  default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
18682                  custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
18683                  no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
18684                </div>
18685              </file>
18686              <file name="protractor.js" type="protractor">
18687                it('should init with 1234.56', function() {
18688                  expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
18689                  expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
18690                  expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
18691                });
18692                it('should update', function() {
18693                  if (browser.params.browser == 'safari') {
18694                    // Safari does not understand the minus key. See
18695                    // https://github.com/angular/protractor/issues/481
18696                    return;
18697                  }
18698                  element(by.model('amount')).clear();
18699                  element(by.model('amount')).sendKeys('-1234');
18700                  expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
18701                  expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
18702                  expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
18703                });
18704              </file>
18705            </example>
18706          */
18707         currencyFilter.$inject = ['$locale'];
18708         function currencyFilter($locale) {
18709           var formats = $locale.NUMBER_FORMATS;
18710           return function(amount, currencySymbol, fractionSize) {
18711             if (isUndefined(currencySymbol)) {
18712               currencySymbol = formats.CURRENCY_SYM;
18713             }
18714
18715             if (isUndefined(fractionSize)) {
18716               fractionSize = formats.PATTERNS[1].maxFrac;
18717             }
18718
18719             // if null or undefined pass it through
18720             return (amount == null)
18721                 ? amount
18722                 : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
18723                     replace(/\u00A4/g, currencySymbol);
18724           };
18725         }
18726
18727         /**
18728          * @ngdoc filter
18729          * @name number
18730          * @kind function
18731          *
18732          * @description
18733          * Formats a number as text.
18734          *
18735          * If the input is null or undefined, it will just be returned.
18736          * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
18737          * If the input is not a number an empty string is returned.
18738          *
18739          *
18740          * @param {number|string} number Number to format.
18741          * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
18742          * If this is not provided then the fraction size is computed from the current locale's number
18743          * formatting pattern. In the case of the default locale, it will be 3.
18744          * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
18745          *
18746          * @example
18747            <example module="numberFilterExample">
18748              <file name="index.html">
18749                <script>
18750                  angular.module('numberFilterExample', [])
18751                    .controller('ExampleController', ['$scope', function($scope) {
18752                      $scope.val = 1234.56789;
18753                    }]);
18754                </script>
18755                <div ng-controller="ExampleController">
18756                  <label>Enter number: <input ng-model='val'></label><br>
18757                  Default formatting: <span id='number-default'>{{val | number}}</span><br>
18758                  No fractions: <span>{{val | number:0}}</span><br>
18759                  Negative number: <span>{{-val | number:4}}</span>
18760                </div>
18761              </file>
18762              <file name="protractor.js" type="protractor">
18763                it('should format numbers', function() {
18764                  expect(element(by.id('number-default')).getText()).toBe('1,234.568');
18765                  expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
18766                  expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
18767                });
18768
18769                it('should update', function() {
18770                  element(by.model('val')).clear();
18771                  element(by.model('val')).sendKeys('3374.333');
18772                  expect(element(by.id('number-default')).getText()).toBe('3,374.333');
18773                  expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
18774                  expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
18775               });
18776              </file>
18777            </example>
18778          */
18779
18780
18781         numberFilter.$inject = ['$locale'];
18782         function numberFilter($locale) {
18783           var formats = $locale.NUMBER_FORMATS;
18784           return function(number, fractionSize) {
18785
18786             // if null or undefined pass it through
18787             return (number == null)
18788                 ? number
18789                 : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
18790                                fractionSize);
18791           };
18792         }
18793
18794         var DECIMAL_SEP = '.';
18795         function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
18796           if (isObject(number)) return '';
18797
18798           var isNegative = number < 0;
18799           number = Math.abs(number);
18800
18801           var isInfinity = number === Infinity;
18802           if (!isInfinity && !isFinite(number)) return '';
18803
18804           var numStr = number + '',
18805               formatedText = '',
18806               hasExponent = false,
18807               parts = [];
18808
18809           if (isInfinity) formatedText = '\u221e';
18810
18811           if (!isInfinity && numStr.indexOf('e') !== -1) {
18812             var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
18813             if (match && match[2] == '-' && match[3] > fractionSize + 1) {
18814               number = 0;
18815             } else {
18816               formatedText = numStr;
18817               hasExponent = true;
18818             }
18819           }
18820
18821           if (!isInfinity && !hasExponent) {
18822             var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
18823
18824             // determine fractionSize if it is not specified
18825             if (isUndefined(fractionSize)) {
18826               fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
18827             }
18828
18829             // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
18830             // inspired by:
18831             // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
18832             number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
18833
18834             var fraction = ('' + number).split(DECIMAL_SEP);
18835             var whole = fraction[0];
18836             fraction = fraction[1] || '';
18837
18838             var i, pos = 0,
18839                 lgroup = pattern.lgSize,
18840                 group = pattern.gSize;
18841
18842             if (whole.length >= (lgroup + group)) {
18843               pos = whole.length - lgroup;
18844               for (i = 0; i < pos; i++) {
18845                 if ((pos - i) % group === 0 && i !== 0) {
18846                   formatedText += groupSep;
18847                 }
18848                 formatedText += whole.charAt(i);
18849               }
18850             }
18851
18852             for (i = pos; i < whole.length; i++) {
18853               if ((whole.length - i) % lgroup === 0 && i !== 0) {
18854                 formatedText += groupSep;
18855               }
18856               formatedText += whole.charAt(i);
18857             }
18858
18859             // format fraction part.
18860             while (fraction.length < fractionSize) {
18861               fraction += '0';
18862             }
18863
18864             if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
18865           } else {
18866             if (fractionSize > 0 && number < 1) {
18867               formatedText = number.toFixed(fractionSize);
18868               number = parseFloat(formatedText);
18869               formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
18870             }
18871           }
18872
18873           if (number === 0) {
18874             isNegative = false;
18875           }
18876
18877           parts.push(isNegative ? pattern.negPre : pattern.posPre,
18878                      formatedText,
18879                      isNegative ? pattern.negSuf : pattern.posSuf);
18880           return parts.join('');
18881         }
18882
18883         function padNumber(num, digits, trim) {
18884           var neg = '';
18885           if (num < 0) {
18886             neg =  '-';
18887             num = -num;
18888           }
18889           num = '' + num;
18890           while (num.length < digits) num = '0' + num;
18891           if (trim) {
18892             num = num.substr(num.length - digits);
18893           }
18894           return neg + num;
18895         }
18896
18897
18898         function dateGetter(name, size, offset, trim) {
18899           offset = offset || 0;
18900           return function(date) {
18901             var value = date['get' + name]();
18902             if (offset > 0 || value > -offset) {
18903               value += offset;
18904             }
18905             if (value === 0 && offset == -12) value = 12;
18906             return padNumber(value, size, trim);
18907           };
18908         }
18909
18910         function dateStrGetter(name, shortForm) {
18911           return function(date, formats) {
18912             var value = date['get' + name]();
18913             var get = uppercase(shortForm ? ('SHORT' + name) : name);
18914
18915             return formats[get][value];
18916           };
18917         }
18918
18919         function timeZoneGetter(date, formats, offset) {
18920           var zone = -1 * offset;
18921           var paddedZone = (zone >= 0) ? "+" : "";
18922
18923           paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
18924                         padNumber(Math.abs(zone % 60), 2);
18925
18926           return paddedZone;
18927         }
18928
18929         function getFirstThursdayOfYear(year) {
18930             // 0 = index of January
18931             var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
18932             // 4 = index of Thursday (+1 to account for 1st = 5)
18933             // 11 = index of *next* Thursday (+1 account for 1st = 12)
18934             return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
18935         }
18936
18937         function getThursdayThisWeek(datetime) {
18938             return new Date(datetime.getFullYear(), datetime.getMonth(),
18939               // 4 = index of Thursday
18940               datetime.getDate() + (4 - datetime.getDay()));
18941         }
18942
18943         function weekGetter(size) {
18944            return function(date) {
18945               var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
18946                  thisThurs = getThursdayThisWeek(date);
18947
18948               var diff = +thisThurs - +firstThurs,
18949                  result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
18950
18951               return padNumber(result, size);
18952            };
18953         }
18954
18955         function ampmGetter(date, formats) {
18956           return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
18957         }
18958
18959         function eraGetter(date, formats) {
18960           return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
18961         }
18962
18963         function longEraGetter(date, formats) {
18964           return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
18965         }
18966
18967         var DATE_FORMATS = {
18968           yyyy: dateGetter('FullYear', 4),
18969             yy: dateGetter('FullYear', 2, 0, true),
18970              y: dateGetter('FullYear', 1),
18971           MMMM: dateStrGetter('Month'),
18972            MMM: dateStrGetter('Month', true),
18973             MM: dateGetter('Month', 2, 1),
18974              M: dateGetter('Month', 1, 1),
18975             dd: dateGetter('Date', 2),
18976              d: dateGetter('Date', 1),
18977             HH: dateGetter('Hours', 2),
18978              H: dateGetter('Hours', 1),
18979             hh: dateGetter('Hours', 2, -12),
18980              h: dateGetter('Hours', 1, -12),
18981             mm: dateGetter('Minutes', 2),
18982              m: dateGetter('Minutes', 1),
18983             ss: dateGetter('Seconds', 2),
18984              s: dateGetter('Seconds', 1),
18985              // while ISO 8601 requires fractions to be prefixed with `.` or `,`
18986              // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
18987            sss: dateGetter('Milliseconds', 3),
18988           EEEE: dateStrGetter('Day'),
18989            EEE: dateStrGetter('Day', true),
18990              a: ampmGetter,
18991              Z: timeZoneGetter,
18992             ww: weekGetter(2),
18993              w: weekGetter(1),
18994              G: eraGetter,
18995              GG: eraGetter,
18996              GGG: eraGetter,
18997              GGGG: longEraGetter
18998         };
18999
19000         var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
19001             NUMBER_STRING = /^\-?\d+$/;
19002
19003         /**
19004          * @ngdoc filter
19005          * @name date
19006          * @kind function
19007          *
19008          * @description
19009          *   Formats `date` to a string based on the requested `format`.
19010          *
19011          *   `format` string can be composed of the following elements:
19012          *
19013          *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
19014          *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
19015          *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
19016          *   * `'MMMM'`: Month in year (January-December)
19017          *   * `'MMM'`: Month in year (Jan-Dec)
19018          *   * `'MM'`: Month in year, padded (01-12)
19019          *   * `'M'`: Month in year (1-12)
19020          *   * `'dd'`: Day in month, padded (01-31)
19021          *   * `'d'`: Day in month (1-31)
19022          *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
19023          *   * `'EEE'`: Day in Week, (Sun-Sat)
19024          *   * `'HH'`: Hour in day, padded (00-23)
19025          *   * `'H'`: Hour in day (0-23)
19026          *   * `'hh'`: Hour in AM/PM, padded (01-12)
19027          *   * `'h'`: Hour in AM/PM, (1-12)
19028          *   * `'mm'`: Minute in hour, padded (00-59)
19029          *   * `'m'`: Minute in hour (0-59)
19030          *   * `'ss'`: Second in minute, padded (00-59)
19031          *   * `'s'`: Second in minute (0-59)
19032          *   * `'sss'`: Millisecond in second, padded (000-999)
19033          *   * `'a'`: AM/PM marker
19034          *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
19035          *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
19036          *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
19037          *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
19038          *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
19039          *
19040          *   `format` string can also be one of the following predefined
19041          *   {@link guide/i18n localizable formats}:
19042          *
19043          *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
19044          *     (e.g. Sep 3, 2010 12:05:08 PM)
19045          *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
19046          *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
19047          *     (e.g. Friday, September 3, 2010)
19048          *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
19049          *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
19050          *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
19051          *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
19052          *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
19053          *
19054          *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
19055          *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
19056          *   (e.g. `"h 'o''clock'"`).
19057          *
19058          * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
19059          *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
19060          *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
19061          *    specified in the string input, the time is considered to be in the local timezone.
19062          * @param {string=} format Formatting rules (see Description). If not specified,
19063          *    `mediumDate` is used.
19064          * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
19065          *    continental US time zone abbreviations, but for general use, use a time zone offset, for
19066          *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
19067          *    If not specified, the timezone of the browser will be used.
19068          * @returns {string} Formatted string or the input if input is not recognized as date/millis.
19069          *
19070          * @example
19071            <example>
19072              <file name="index.html">
19073                <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
19074                    <span>{{1288323623006 | date:'medium'}}</span><br>
19075                <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
19076                   <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
19077                <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
19078                   <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
19079                <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
19080                   <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
19081              </file>
19082              <file name="protractor.js" type="protractor">
19083                it('should format date', function() {
19084                  expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
19085                     toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
19086                  expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
19087                     toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
19088                  expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
19089                     toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
19090                  expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
19091                     toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
19092                });
19093              </file>
19094            </example>
19095          */
19096         dateFilter.$inject = ['$locale'];
19097         function dateFilter($locale) {
19098
19099
19100           var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
19101                              // 1        2       3         4          5          6          7          8  9     10      11
19102           function jsonStringToDate(string) {
19103             var match;
19104             if (match = string.match(R_ISO8601_STR)) {
19105               var date = new Date(0),
19106                   tzHour = 0,
19107                   tzMin  = 0,
19108                   dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
19109                   timeSetter = match[8] ? date.setUTCHours : date.setHours;
19110
19111               if (match[9]) {
19112                 tzHour = toInt(match[9] + match[10]);
19113                 tzMin = toInt(match[9] + match[11]);
19114               }
19115               dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
19116               var h = toInt(match[4] || 0) - tzHour;
19117               var m = toInt(match[5] || 0) - tzMin;
19118               var s = toInt(match[6] || 0);
19119               var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
19120               timeSetter.call(date, h, m, s, ms);
19121               return date;
19122             }
19123             return string;
19124           }
19125
19126
19127           return function(date, format, timezone) {
19128             var text = '',
19129                 parts = [],
19130                 fn, match;
19131
19132             format = format || 'mediumDate';
19133             format = $locale.DATETIME_FORMATS[format] || format;
19134             if (isString(date)) {
19135               date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
19136             }
19137
19138             if (isNumber(date)) {
19139               date = new Date(date);
19140             }
19141
19142             if (!isDate(date) || !isFinite(date.getTime())) {
19143               return date;
19144             }
19145
19146             while (format) {
19147               match = DATE_FORMATS_SPLIT.exec(format);
19148               if (match) {
19149                 parts = concat(parts, match, 1);
19150                 format = parts.pop();
19151               } else {
19152                 parts.push(format);
19153                 format = null;
19154               }
19155             }
19156
19157             var dateTimezoneOffset = date.getTimezoneOffset();
19158             if (timezone) {
19159               dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
19160               date = convertTimezoneToLocal(date, timezone, true);
19161             }
19162             forEach(parts, function(value) {
19163               fn = DATE_FORMATS[value];
19164               text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
19165                          : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
19166             });
19167
19168             return text;
19169           };
19170         }
19171
19172
19173         /**
19174          * @ngdoc filter
19175          * @name json
19176          * @kind function
19177          *
19178          * @description
19179          *   Allows you to convert a JavaScript object into JSON string.
19180          *
19181          *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
19182          *   the binding is automatically converted to JSON.
19183          *
19184          * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
19185          * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
19186          * @returns {string} JSON string.
19187          *
19188          *
19189          * @example
19190            <example>
19191              <file name="index.html">
19192                <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
19193                <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
19194              </file>
19195              <file name="protractor.js" type="protractor">
19196                it('should jsonify filtered objects', function() {
19197                  expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
19198                  expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
19199                });
19200              </file>
19201            </example>
19202          *
19203          */
19204         function jsonFilter() {
19205           return function(object, spacing) {
19206             if (isUndefined(spacing)) {
19207                 spacing = 2;
19208             }
19209             return toJson(object, spacing);
19210           };
19211         }
19212
19213
19214         /**
19215          * @ngdoc filter
19216          * @name lowercase
19217          * @kind function
19218          * @description
19219          * Converts string to lowercase.
19220          * @see angular.lowercase
19221          */
19222         var lowercaseFilter = valueFn(lowercase);
19223
19224
19225         /**
19226          * @ngdoc filter
19227          * @name uppercase
19228          * @kind function
19229          * @description
19230          * Converts string to uppercase.
19231          * @see angular.uppercase
19232          */
19233         var uppercaseFilter = valueFn(uppercase);
19234
19235         /**
19236          * @ngdoc filter
19237          * @name limitTo
19238          * @kind function
19239          *
19240          * @description
19241          * Creates a new array or string containing only a specified number of elements. The elements
19242          * are taken from either the beginning or the end of the source array, string or number, as specified by
19243          * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
19244          * converted to a string.
19245          *
19246          * @param {Array|string|number} input Source array, string or number to be limited.
19247          * @param {string|number} limit The length of the returned array or string. If the `limit` number
19248          *     is positive, `limit` number of items from the beginning of the source array/string are copied.
19249          *     If the number is negative, `limit` number  of items from the end of the source array/string
19250          *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
19251          *     the input will be returned unchanged.
19252          * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
19253          *     indicates an offset from the end of `input`. Defaults to `0`.
19254          * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
19255          *     had less than `limit` elements.
19256          *
19257          * @example
19258            <example module="limitToExample">
19259              <file name="index.html">
19260                <script>
19261                  angular.module('limitToExample', [])
19262                    .controller('ExampleController', ['$scope', function($scope) {
19263                      $scope.numbers = [1,2,3,4,5,6,7,8,9];
19264                      $scope.letters = "abcdefghi";
19265                      $scope.longNumber = 2345432342;
19266                      $scope.numLimit = 3;
19267                      $scope.letterLimit = 3;
19268                      $scope.longNumberLimit = 3;
19269                    }]);
19270                </script>
19271                <div ng-controller="ExampleController">
19272                  <label>
19273                     Limit {{numbers}} to:
19274                     <input type="number" step="1" ng-model="numLimit">
19275                  </label>
19276                  <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
19277                  <label>
19278                     Limit {{letters}} to:
19279                     <input type="number" step="1" ng-model="letterLimit">
19280                  </label>
19281                  <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
19282                  <label>
19283                     Limit {{longNumber}} to:
19284                     <input type="number" step="1" ng-model="longNumberLimit">
19285                  </label>
19286                  <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
19287                </div>
19288              </file>
19289              <file name="protractor.js" type="protractor">
19290                var numLimitInput = element(by.model('numLimit'));
19291                var letterLimitInput = element(by.model('letterLimit'));
19292                var longNumberLimitInput = element(by.model('longNumberLimit'));
19293                var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
19294                var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
19295                var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
19296
19297                it('should limit the number array to first three items', function() {
19298                  expect(numLimitInput.getAttribute('value')).toBe('3');
19299                  expect(letterLimitInput.getAttribute('value')).toBe('3');
19300                  expect(longNumberLimitInput.getAttribute('value')).toBe('3');
19301                  expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
19302                  expect(limitedLetters.getText()).toEqual('Output letters: abc');
19303                  expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
19304                });
19305
19306                // There is a bug in safari and protractor that doesn't like the minus key
19307                // it('should update the output when -3 is entered', function() {
19308                //   numLimitInput.clear();
19309                //   numLimitInput.sendKeys('-3');
19310                //   letterLimitInput.clear();
19311                //   letterLimitInput.sendKeys('-3');
19312                //   longNumberLimitInput.clear();
19313                //   longNumberLimitInput.sendKeys('-3');
19314                //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
19315                //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
19316                //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
19317                // });
19318
19319                it('should not exceed the maximum size of input array', function() {
19320                  numLimitInput.clear();
19321                  numLimitInput.sendKeys('100');
19322                  letterLimitInput.clear();
19323                  letterLimitInput.sendKeys('100');
19324                  longNumberLimitInput.clear();
19325                  longNumberLimitInput.sendKeys('100');
19326                  expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
19327                  expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
19328                  expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
19329                });
19330              </file>
19331            </example>
19332         */
19333         function limitToFilter() {
19334           return function(input, limit, begin) {
19335             if (Math.abs(Number(limit)) === Infinity) {
19336               limit = Number(limit);
19337             } else {
19338               limit = toInt(limit);
19339             }
19340             if (isNaN(limit)) return input;
19341
19342             if (isNumber(input)) input = input.toString();
19343             if (!isArray(input) && !isString(input)) return input;
19344
19345             begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
19346             begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
19347
19348             if (limit >= 0) {
19349               return input.slice(begin, begin + limit);
19350             } else {
19351               if (begin === 0) {
19352                 return input.slice(limit, input.length);
19353               } else {
19354                 return input.slice(Math.max(0, begin + limit), begin);
19355               }
19356             }
19357           };
19358         }
19359
19360         /**
19361          * @ngdoc filter
19362          * @name orderBy
19363          * @kind function
19364          *
19365          * @description
19366          * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
19367          * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
19368          * as expected, make sure they are actually being saved as numbers and not strings.
19369          *
19370          * @param {Array} array The array to sort.
19371          * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
19372          *    used by the comparator to determine the order of elements.
19373          *
19374          *    Can be one of:
19375          *
19376          *    - `function`: Getter function. The result of this function will be sorted using the
19377          *      `<`, `===`, `>` operator.
19378          *    - `string`: An Angular expression. The result of this expression is used to compare elements
19379          *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
19380          *      3 first characters of a property called `name`). The result of a constant expression
19381          *      is interpreted as a property name to be used in comparisons (for example `"special name"`
19382          *      to sort object by the value of their `special name` property). An expression can be
19383          *      optionally prefixed with `+` or `-` to control ascending or descending sort order
19384          *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
19385          *      element itself is used to compare where sorting.
19386          *    - `Array`: An array of function or string predicates. The first predicate in the array
19387          *      is used for sorting, but when two items are equivalent, the next predicate is used.
19388          *
19389          *    If the predicate is missing or empty then it defaults to `'+'`.
19390          *
19391          * @param {boolean=} reverse Reverse the order of the array.
19392          * @returns {Array} Sorted copy of the source array.
19393          *
19394          *
19395          * @example
19396          * The example below demonstrates a simple ngRepeat, where the data is sorted
19397          * by age in descending order (predicate is set to `'-age'`).
19398          * `reverse` is not set, which means it defaults to `false`.
19399            <example module="orderByExample">
19400              <file name="index.html">
19401                <script>
19402                  angular.module('orderByExample', [])
19403                    .controller('ExampleController', ['$scope', function($scope) {
19404                      $scope.friends =
19405                          [{name:'John', phone:'555-1212', age:10},
19406                           {name:'Mary', phone:'555-9876', age:19},
19407                           {name:'Mike', phone:'555-4321', age:21},
19408                           {name:'Adam', phone:'555-5678', age:35},
19409                           {name:'Julie', phone:'555-8765', age:29}];
19410                    }]);
19411                </script>
19412                <div ng-controller="ExampleController">
19413                  <table class="friend">
19414                    <tr>
19415                      <th>Name</th>
19416                      <th>Phone Number</th>
19417                      <th>Age</th>
19418                    </tr>
19419                    <tr ng-repeat="friend in friends | orderBy:'-age'">
19420                      <td>{{friend.name}}</td>
19421                      <td>{{friend.phone}}</td>
19422                      <td>{{friend.age}}</td>
19423                    </tr>
19424                  </table>
19425                </div>
19426              </file>
19427            </example>
19428          *
19429          * The predicate and reverse parameters can be controlled dynamically through scope properties,
19430          * as shown in the next example.
19431          * @example
19432            <example module="orderByExample">
19433              <file name="index.html">
19434                <script>
19435                  angular.module('orderByExample', [])
19436                    .controller('ExampleController', ['$scope', function($scope) {
19437                      $scope.friends =
19438                          [{name:'John', phone:'555-1212', age:10},
19439                           {name:'Mary', phone:'555-9876', age:19},
19440                           {name:'Mike', phone:'555-4321', age:21},
19441                           {name:'Adam', phone:'555-5678', age:35},
19442                           {name:'Julie', phone:'555-8765', age:29}];
19443                      $scope.predicate = 'age';
19444                      $scope.reverse = true;
19445                      $scope.order = function(predicate) {
19446                        $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
19447                        $scope.predicate = predicate;
19448                      };
19449                    }]);
19450                </script>
19451                <style type="text/css">
19452                  .sortorder:after {
19453                    content: '\25b2';
19454                  }
19455                  .sortorder.reverse:after {
19456                    content: '\25bc';
19457                  }
19458                </style>
19459                <div ng-controller="ExampleController">
19460                  <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
19461                  <hr/>
19462                  [ <a href="" ng-click="predicate=''">unsorted</a> ]
19463                  <table class="friend">
19464                    <tr>
19465                      <th>
19466                        <a href="" ng-click="order('name')">Name</a>
19467                        <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
19468                      </th>
19469                      <th>
19470                        <a href="" ng-click="order('phone')">Phone Number</a>
19471                        <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
19472                      </th>
19473                      <th>
19474                        <a href="" ng-click="order('age')">Age</a>
19475                        <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
19476                      </th>
19477                    </tr>
19478                    <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
19479                      <td>{{friend.name}}</td>
19480                      <td>{{friend.phone}}</td>
19481                      <td>{{friend.age}}</td>
19482                    </tr>
19483                  </table>
19484                </div>
19485              </file>
19486            </example>
19487          *
19488          * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
19489          * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
19490          * desired parameters.
19491          *
19492          * Example:
19493          *
19494          * @example
19495           <example module="orderByExample">
19496             <file name="index.html">
19497               <div ng-controller="ExampleController">
19498                 <table class="friend">
19499                   <tr>
19500                     <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
19501                       (<a href="" ng-click="order('-name',false)">^</a>)</th>
19502                     <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
19503                     <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
19504                   </tr>
19505                   <tr ng-repeat="friend in friends">
19506                     <td>{{friend.name}}</td>
19507                     <td>{{friend.phone}}</td>
19508                     <td>{{friend.age}}</td>
19509                   </tr>
19510                 </table>
19511               </div>
19512             </file>
19513
19514             <file name="script.js">
19515               angular.module('orderByExample', [])
19516                 .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
19517                   var orderBy = $filter('orderBy');
19518                   $scope.friends = [
19519                     { name: 'John',    phone: '555-1212',    age: 10 },
19520                     { name: 'Mary',    phone: '555-9876',    age: 19 },
19521                     { name: 'Mike',    phone: '555-4321',    age: 21 },
19522                     { name: 'Adam',    phone: '555-5678',    age: 35 },
19523                     { name: 'Julie',   phone: '555-8765',    age: 29 }
19524                   ];
19525                   $scope.order = function(predicate, reverse) {
19526                     $scope.friends = orderBy($scope.friends, predicate, reverse);
19527                   };
19528                   $scope.order('-age',false);
19529                 }]);
19530             </file>
19531         </example>
19532          */
19533         orderByFilter.$inject = ['$parse'];
19534         function orderByFilter($parse) {
19535           return function(array, sortPredicate, reverseOrder) {
19536
19537             if (!(isArrayLike(array))) return array;
19538
19539             if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
19540             if (sortPredicate.length === 0) { sortPredicate = ['+']; }
19541
19542             var predicates = processPredicates(sortPredicate, reverseOrder);
19543             // Add a predicate at the end that evaluates to the element index. This makes the
19544             // sort stable as it works as a tie-breaker when all the input predicates cannot
19545             // distinguish between two elements.
19546             predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
19547
19548             // The next three lines are a version of a Swartzian Transform idiom from Perl
19549             // (sometimes called the Decorate-Sort-Undecorate idiom)
19550             // See https://en.wikipedia.org/wiki/Schwartzian_transform
19551             var compareValues = Array.prototype.map.call(array, getComparisonObject);
19552             compareValues.sort(doComparison);
19553             array = compareValues.map(function(item) { return item.value; });
19554
19555             return array;
19556
19557             function getComparisonObject(value, index) {
19558               return {
19559                 value: value,
19560                 predicateValues: predicates.map(function(predicate) {
19561                   return getPredicateValue(predicate.get(value), index);
19562                 })
19563               };
19564             }
19565
19566             function doComparison(v1, v2) {
19567               var result = 0;
19568               for (var index=0, length = predicates.length; index < length; ++index) {
19569                 result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
19570                 if (result) break;
19571               }
19572               return result;
19573             }
19574           };
19575
19576           function processPredicates(sortPredicate, reverseOrder) {
19577             reverseOrder = reverseOrder ? -1 : 1;
19578             return sortPredicate.map(function(predicate) {
19579               var descending = 1, get = identity;
19580
19581               if (isFunction(predicate)) {
19582                 get = predicate;
19583               } else if (isString(predicate)) {
19584                 if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
19585                   descending = predicate.charAt(0) == '-' ? -1 : 1;
19586                   predicate = predicate.substring(1);
19587                 }
19588                 if (predicate !== '') {
19589                   get = $parse(predicate);
19590                   if (get.constant) {
19591                     var key = get();
19592                     get = function(value) { return value[key]; };
19593                   }
19594                 }
19595               }
19596               return { get: get, descending: descending * reverseOrder };
19597             });
19598           }
19599
19600           function isPrimitive(value) {
19601             switch (typeof value) {
19602               case 'number': /* falls through */
19603               case 'boolean': /* falls through */
19604               case 'string':
19605                 return true;
19606               default:
19607                 return false;
19608             }
19609           }
19610
19611           function objectValue(value, index) {
19612             // If `valueOf` is a valid function use that
19613             if (typeof value.valueOf === 'function') {
19614               value = value.valueOf();
19615               if (isPrimitive(value)) return value;
19616             }
19617             // If `toString` is a valid function and not the one from `Object.prototype` use that
19618             if (hasCustomToString(value)) {
19619               value = value.toString();
19620               if (isPrimitive(value)) return value;
19621             }
19622             // We have a basic object so we use the position of the object in the collection
19623             return index;
19624           }
19625
19626           function getPredicateValue(value, index) {
19627             var type = typeof value;
19628             if (value === null) {
19629               type = 'string';
19630               value = 'null';
19631             } else if (type === 'string') {
19632               value = value.toLowerCase();
19633             } else if (type === 'object') {
19634               value = objectValue(value, index);
19635             }
19636             return { value: value, type: type };
19637           }
19638
19639           function compare(v1, v2) {
19640             var result = 0;
19641             if (v1.type === v2.type) {
19642               if (v1.value !== v2.value) {
19643                 result = v1.value < v2.value ? -1 : 1;
19644               }
19645             } else {
19646               result = v1.type < v2.type ? -1 : 1;
19647             }
19648             return result;
19649           }
19650         }
19651
19652         function ngDirective(directive) {
19653           if (isFunction(directive)) {
19654             directive = {
19655               link: directive
19656             };
19657           }
19658           directive.restrict = directive.restrict || 'AC';
19659           return valueFn(directive);
19660         }
19661
19662         /**
19663          * @ngdoc directive
19664          * @name a
19665          * @restrict E
19666          *
19667          * @description
19668          * Modifies the default behavior of the html A tag so that the default action is prevented when
19669          * the href attribute is empty.
19670          *
19671          * This change permits the easy creation of action links with the `ngClick` directive
19672          * without changing the location or causing page reloads, e.g.:
19673          * `<a href="" ng-click="list.addItem()">Add Item</a>`
19674          */
19675         var htmlAnchorDirective = valueFn({
19676           restrict: 'E',
19677           compile: function(element, attr) {
19678             if (!attr.href && !attr.xlinkHref) {
19679               return function(scope, element) {
19680                 // If the linked element is not an anchor tag anymore, do nothing
19681                 if (element[0].nodeName.toLowerCase() !== 'a') return;
19682
19683                 // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
19684                 var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
19685                            'xlink:href' : 'href';
19686                 element.on('click', function(event) {
19687                   // if we have no href url, then don't navigate anywhere.
19688                   if (!element.attr(href)) {
19689                     event.preventDefault();
19690                   }
19691                 });
19692               };
19693             }
19694           }
19695         });
19696
19697         /**
19698          * @ngdoc directive
19699          * @name ngHref
19700          * @restrict A
19701          * @priority 99
19702          *
19703          * @description
19704          * Using Angular markup like `{{hash}}` in an href attribute will
19705          * make the link go to the wrong URL if the user clicks it before
19706          * Angular has a chance to replace the `{{hash}}` markup with its
19707          * value. Until Angular replaces the markup the link will be broken
19708          * and will most likely return a 404 error. The `ngHref` directive
19709          * solves this problem.
19710          *
19711          * The wrong way to write it:
19712          * ```html
19713          * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19714          * ```
19715          *
19716          * The correct way to write it:
19717          * ```html
19718          * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19719          * ```
19720          *
19721          * @element A
19722          * @param {template} ngHref any string which can contain `{{}}` markup.
19723          *
19724          * @example
19725          * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
19726          * in links and their different behaviors:
19727             <example>
19728               <file name="index.html">
19729                 <input ng-model="value" /><br />
19730                 <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
19731                 <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
19732                 <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
19733                 <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
19734                 <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
19735                 <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
19736               </file>
19737               <file name="protractor.js" type="protractor">
19738                 it('should execute ng-click but not reload when href without value', function() {
19739                   element(by.id('link-1')).click();
19740                   expect(element(by.model('value')).getAttribute('value')).toEqual('1');
19741                   expect(element(by.id('link-1')).getAttribute('href')).toBe('');
19742                 });
19743
19744                 it('should execute ng-click but not reload when href empty string', function() {
19745                   element(by.id('link-2')).click();
19746                   expect(element(by.model('value')).getAttribute('value')).toEqual('2');
19747                   expect(element(by.id('link-2')).getAttribute('href')).toBe('');
19748                 });
19749
19750                 it('should execute ng-click and change url when ng-href specified', function() {
19751                   expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
19752
19753                   element(by.id('link-3')).click();
19754
19755                   // At this point, we navigate away from an Angular page, so we need
19756                   // to use browser.driver to get the base webdriver.
19757
19758                   browser.wait(function() {
19759                     return browser.driver.getCurrentUrl().then(function(url) {
19760                       return url.match(/\/123$/);
19761                     });
19762                   }, 5000, 'page should navigate to /123');
19763                 });
19764
19765                 it('should execute ng-click but not reload when href empty string and name specified', function() {
19766                   element(by.id('link-4')).click();
19767                   expect(element(by.model('value')).getAttribute('value')).toEqual('4');
19768                   expect(element(by.id('link-4')).getAttribute('href')).toBe('');
19769                 });
19770
19771                 it('should execute ng-click but not reload when no href but name specified', function() {
19772                   element(by.id('link-5')).click();
19773                   expect(element(by.model('value')).getAttribute('value')).toEqual('5');
19774                   expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
19775                 });
19776
19777                 it('should only change url when only ng-href', function() {
19778                   element(by.model('value')).clear();
19779                   element(by.model('value')).sendKeys('6');
19780                   expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
19781
19782                   element(by.id('link-6')).click();
19783
19784                   // At this point, we navigate away from an Angular page, so we need
19785                   // to use browser.driver to get the base webdriver.
19786                   browser.wait(function() {
19787                     return browser.driver.getCurrentUrl().then(function(url) {
19788                       return url.match(/\/6$/);
19789                     });
19790                   }, 5000, 'page should navigate to /6');
19791                 });
19792               </file>
19793             </example>
19794          */
19795
19796         /**
19797          * @ngdoc directive
19798          * @name ngSrc
19799          * @restrict A
19800          * @priority 99
19801          *
19802          * @description
19803          * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
19804          * work right: The browser will fetch from the URL with the literal
19805          * text `{{hash}}` until Angular replaces the expression inside
19806          * `{{hash}}`. The `ngSrc` directive solves this problem.
19807          *
19808          * The buggy way to write it:
19809          * ```html
19810          * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
19811          * ```
19812          *
19813          * The correct way to write it:
19814          * ```html
19815          * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
19816          * ```
19817          *
19818          * @element IMG
19819          * @param {template} ngSrc any string which can contain `{{}}` markup.
19820          */
19821
19822         /**
19823          * @ngdoc directive
19824          * @name ngSrcset
19825          * @restrict A
19826          * @priority 99
19827          *
19828          * @description
19829          * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
19830          * work right: The browser will fetch from the URL with the literal
19831          * text `{{hash}}` until Angular replaces the expression inside
19832          * `{{hash}}`. The `ngSrcset` directive solves this problem.
19833          *
19834          * The buggy way to write it:
19835          * ```html
19836          * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
19837          * ```
19838          *
19839          * The correct way to write it:
19840          * ```html
19841          * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
19842          * ```
19843          *
19844          * @element IMG
19845          * @param {template} ngSrcset any string which can contain `{{}}` markup.
19846          */
19847
19848         /**
19849          * @ngdoc directive
19850          * @name ngDisabled
19851          * @restrict A
19852          * @priority 100
19853          *
19854          * @description
19855          *
19856          * This directive sets the `disabled` attribute on the element if the
19857          * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
19858          *
19859          * A special directive is necessary because we cannot use interpolation inside the `disabled`
19860          * attribute.  The following example would make the button enabled on Chrome/Firefox
19861          * but not on older IEs:
19862          *
19863          * ```html
19864          * <!-- See below for an example of ng-disabled being used correctly -->
19865          * <div ng-init="isDisabled = false">
19866          *  <button disabled="{{isDisabled}}">Disabled</button>
19867          * </div>
19868          * ```
19869          *
19870          * This is because the HTML specification does not require browsers to preserve the values of
19871          * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
19872          * If we put an Angular interpolation expression into such an attribute then the
19873          * binding information would be lost when the browser removes the attribute.
19874          *
19875          * @example
19876             <example>
19877               <file name="index.html">
19878                 <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
19879                 <button ng-model="button" ng-disabled="checked">Button</button>
19880               </file>
19881               <file name="protractor.js" type="protractor">
19882                 it('should toggle button', function() {
19883                   expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
19884                   element(by.model('checked')).click();
19885                   expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
19886                 });
19887               </file>
19888             </example>
19889          *
19890          * @element INPUT
19891          * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
19892          *     then the `disabled` attribute will be set on the element
19893          */
19894
19895
19896         /**
19897          * @ngdoc directive
19898          * @name ngChecked
19899          * @restrict A
19900          * @priority 100
19901          *
19902          * @description
19903          * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
19904          *
19905          * Note that this directive should not be used together with {@link ngModel `ngModel`},
19906          * as this can lead to unexpected behavior.
19907          *
19908          * ### Why do we need `ngChecked`?
19909          *
19910          * The HTML specification does not require browsers to preserve the values of boolean attributes
19911          * such as checked. (Their presence means true and their absence means false.)
19912          * If we put an Angular interpolation expression into such an attribute then the
19913          * binding information would be lost when the browser removes the attribute.
19914          * The `ngChecked` directive solves this problem for the `checked` attribute.
19915          * This complementary directive is not removed by the browser and so provides
19916          * a permanent reliable place to store the binding information.
19917          * @example
19918             <example>
19919               <file name="index.html">
19920                 <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
19921                 <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
19922               </file>
19923               <file name="protractor.js" type="protractor">
19924                 it('should check both checkBoxes', function() {
19925                   expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
19926                   element(by.model('master')).click();
19927                   expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
19928                 });
19929               </file>
19930             </example>
19931          *
19932          * @element INPUT
19933          * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
19934          *     then the `checked` attribute will be set on the element
19935          */
19936
19937
19938         /**
19939          * @ngdoc directive
19940          * @name ngReadonly
19941          * @restrict A
19942          * @priority 100
19943          *
19944          * @description
19945          * The HTML specification does not require browsers to preserve the values of boolean attributes
19946          * such as readonly. (Their presence means true and their absence means false.)
19947          * If we put an Angular interpolation expression into such an attribute then the
19948          * binding information would be lost when the browser removes the attribute.
19949          * The `ngReadonly` directive solves this problem for the `readonly` attribute.
19950          * This complementary directive is not removed by the browser and so provides
19951          * a permanent reliable place to store the binding information.
19952          * @example
19953             <example>
19954               <file name="index.html">
19955                 <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
19956                 <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
19957               </file>
19958               <file name="protractor.js" type="protractor">
19959                 it('should toggle readonly attr', function() {
19960                   expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
19961                   element(by.model('checked')).click();
19962                   expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
19963                 });
19964               </file>
19965             </example>
19966          *
19967          * @element INPUT
19968          * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
19969          *     then special attribute "readonly" will be set on the element
19970          */
19971
19972
19973         /**
19974          * @ngdoc directive
19975          * @name ngSelected
19976          * @restrict A
19977          * @priority 100
19978          *
19979          * @description
19980          * The HTML specification does not require browsers to preserve the values of boolean attributes
19981          * such as selected. (Their presence means true and their absence means false.)
19982          * If we put an Angular interpolation expression into such an attribute then the
19983          * binding information would be lost when the browser removes the attribute.
19984          * The `ngSelected` directive solves this problem for the `selected` attribute.
19985          * This complementary directive is not removed by the browser and so provides
19986          * a permanent reliable place to store the binding information.
19987          *
19988          * @example
19989             <example>
19990               <file name="index.html">
19991                 <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
19992                 <select aria-label="ngSelected demo">
19993                   <option>Hello!</option>
19994                   <option id="greet" ng-selected="selected">Greetings!</option>
19995                 </select>
19996               </file>
19997               <file name="protractor.js" type="protractor">
19998                 it('should select Greetings!', function() {
19999                   expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
20000                   element(by.model('selected')).click();
20001                   expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
20002                 });
20003               </file>
20004             </example>
20005          *
20006          * @element OPTION
20007          * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
20008          *     then special attribute "selected" will be set on the element
20009          */
20010
20011         /**
20012          * @ngdoc directive
20013          * @name ngOpen
20014          * @restrict A
20015          * @priority 100
20016          *
20017          * @description
20018          * The HTML specification does not require browsers to preserve the values of boolean attributes
20019          * such as open. (Their presence means true and their absence means false.)
20020          * If we put an Angular interpolation expression into such an attribute then the
20021          * binding information would be lost when the browser removes the attribute.
20022          * The `ngOpen` directive solves this problem for the `open` attribute.
20023          * This complementary directive is not removed by the browser and so provides
20024          * a permanent reliable place to store the binding information.
20025          * @example
20026              <example>
20027                <file name="index.html">
20028                  <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
20029                  <details id="details" ng-open="open">
20030                     <summary>Show/Hide me</summary>
20031                  </details>
20032                </file>
20033                <file name="protractor.js" type="protractor">
20034                  it('should toggle open', function() {
20035                    expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
20036                    element(by.model('open')).click();
20037                    expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
20038                  });
20039                </file>
20040              </example>
20041          *
20042          * @element DETAILS
20043          * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
20044          *     then special attribute "open" will be set on the element
20045          */
20046
20047         var ngAttributeAliasDirectives = {};
20048
20049         // boolean attrs are evaluated
20050         forEach(BOOLEAN_ATTR, function(propName, attrName) {
20051           // binding to multiple is not supported
20052           if (propName == "multiple") return;
20053
20054           function defaultLinkFn(scope, element, attr) {
20055             scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
20056               attr.$set(attrName, !!value);
20057             });
20058           }
20059
20060           var normalized = directiveNormalize('ng-' + attrName);
20061           var linkFn = defaultLinkFn;
20062
20063           if (propName === 'checked') {
20064             linkFn = function(scope, element, attr) {
20065               // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
20066               if (attr.ngModel !== attr[normalized]) {
20067                 defaultLinkFn(scope, element, attr);
20068               }
20069             };
20070           }
20071
20072           ngAttributeAliasDirectives[normalized] = function() {
20073             return {
20074               restrict: 'A',
20075               priority: 100,
20076               link: linkFn
20077             };
20078           };
20079         });
20080
20081         // aliased input attrs are evaluated
20082         forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
20083           ngAttributeAliasDirectives[ngAttr] = function() {
20084             return {
20085               priority: 100,
20086               link: function(scope, element, attr) {
20087                 //special case ngPattern when a literal regular expression value
20088                 //is used as the expression (this way we don't have to watch anything).
20089                 if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
20090                   var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
20091                   if (match) {
20092                     attr.$set("ngPattern", new RegExp(match[1], match[2]));
20093                     return;
20094                   }
20095                 }
20096
20097                 scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
20098                   attr.$set(ngAttr, value);
20099                 });
20100               }
20101             };
20102           };
20103         });
20104
20105         // ng-src, ng-srcset, ng-href are interpolated
20106         forEach(['src', 'srcset', 'href'], function(attrName) {
20107           var normalized = directiveNormalize('ng-' + attrName);
20108           ngAttributeAliasDirectives[normalized] = function() {
20109             return {
20110               priority: 99, // it needs to run after the attributes are interpolated
20111               link: function(scope, element, attr) {
20112                 var propName = attrName,
20113                     name = attrName;
20114
20115                 if (attrName === 'href' &&
20116                     toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
20117                   name = 'xlinkHref';
20118                   attr.$attr[name] = 'xlink:href';
20119                   propName = null;
20120                 }
20121
20122                 attr.$observe(normalized, function(value) {
20123                   if (!value) {
20124                     if (attrName === 'href') {
20125                       attr.$set(name, null);
20126                     }
20127                     return;
20128                   }
20129
20130                   attr.$set(name, value);
20131
20132                   // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
20133                   // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
20134                   // to set the property as well to achieve the desired effect.
20135                   // we use attr[attrName] value since $set can sanitize the url.
20136                   if (msie && propName) element.prop(propName, attr[name]);
20137                 });
20138               }
20139             };
20140           };
20141         });
20142
20143         /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
20144          */
20145         var nullFormCtrl = {
20146           $addControl: noop,
20147           $$renameControl: nullFormRenameControl,
20148           $removeControl: noop,
20149           $setValidity: noop,
20150           $setDirty: noop,
20151           $setPristine: noop,
20152           $setSubmitted: noop
20153         },
20154         SUBMITTED_CLASS = 'ng-submitted';
20155
20156         function nullFormRenameControl(control, name) {
20157           control.$name = name;
20158         }
20159
20160         /**
20161          * @ngdoc type
20162          * @name form.FormController
20163          *
20164          * @property {boolean} $pristine True if user has not interacted with the form yet.
20165          * @property {boolean} $dirty True if user has already interacted with the form.
20166          * @property {boolean} $valid True if all of the containing forms and controls are valid.
20167          * @property {boolean} $invalid True if at least one containing control or form is invalid.
20168          * @property {boolean} $pending True if at least one containing control or form is pending.
20169          * @property {boolean} $submitted True if user has submitted the form even if its invalid.
20170          *
20171          * @property {Object} $error Is an object hash, containing references to controls or
20172          *  forms with failing validators, where:
20173          *
20174          *  - keys are validation tokens (error names),
20175          *  - values are arrays of controls or forms that have a failing validator for given error name.
20176          *
20177          *  Built-in validation tokens:
20178          *
20179          *  - `email`
20180          *  - `max`
20181          *  - `maxlength`
20182          *  - `min`
20183          *  - `minlength`
20184          *  - `number`
20185          *  - `pattern`
20186          *  - `required`
20187          *  - `url`
20188          *  - `date`
20189          *  - `datetimelocal`
20190          *  - `time`
20191          *  - `week`
20192          *  - `month`
20193          *
20194          * @description
20195          * `FormController` keeps track of all its controls and nested forms as well as the state of them,
20196          * such as being valid/invalid or dirty/pristine.
20197          *
20198          * Each {@link ng.directive:form form} directive creates an instance
20199          * of `FormController`.
20200          *
20201          */
20202         //asks for $scope to fool the BC controller module
20203         FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
20204         function FormController(element, attrs, $scope, $animate, $interpolate) {
20205           var form = this,
20206               controls = [];
20207
20208           // init state
20209           form.$error = {};
20210           form.$$success = {};
20211           form.$pending = undefined;
20212           form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
20213           form.$dirty = false;
20214           form.$pristine = true;
20215           form.$valid = true;
20216           form.$invalid = false;
20217           form.$submitted = false;
20218           form.$$parentForm = nullFormCtrl;
20219
20220           /**
20221            * @ngdoc method
20222            * @name form.FormController#$rollbackViewValue
20223            *
20224            * @description
20225            * Rollback all form controls pending updates to the `$modelValue`.
20226            *
20227            * Updates may be pending by a debounced event or because the input is waiting for a some future
20228            * event defined in `ng-model-options`. This method is typically needed by the reset button of
20229            * a form that uses `ng-model-options` to pend updates.
20230            */
20231           form.$rollbackViewValue = function() {
20232             forEach(controls, function(control) {
20233               control.$rollbackViewValue();
20234             });
20235           };
20236
20237           /**
20238            * @ngdoc method
20239            * @name form.FormController#$commitViewValue
20240            *
20241            * @description
20242            * Commit all form controls pending updates to the `$modelValue`.
20243            *
20244            * Updates may be pending by a debounced event or because the input is waiting for a some future
20245            * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
20246            * usually handles calling this in response to input events.
20247            */
20248           form.$commitViewValue = function() {
20249             forEach(controls, function(control) {
20250               control.$commitViewValue();
20251             });
20252           };
20253
20254           /**
20255            * @ngdoc method
20256            * @name form.FormController#$addControl
20257            * @param {object} control control object, either a {@link form.FormController} or an
20258            * {@link ngModel.NgModelController}
20259            *
20260            * @description
20261            * Register a control with the form. Input elements using ngModelController do this automatically
20262            * when they are linked.
20263            *
20264            * Note that the current state of the control will not be reflected on the new parent form. This
20265            * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
20266            * state.
20267            *
20268            * However, if the method is used programmatically, for example by adding dynamically created controls,
20269            * or controls that have been previously removed without destroying their corresponding DOM element,
20270            * it's the developers responsiblity to make sure the current state propagates to the parent form.
20271            *
20272            * For example, if an input control is added that is already `$dirty` and has `$error` properties,
20273            * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
20274            */
20275           form.$addControl = function(control) {
20276             // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
20277             // and not added to the scope.  Now we throw an error.
20278             assertNotHasOwnProperty(control.$name, 'input');
20279             controls.push(control);
20280
20281             if (control.$name) {
20282               form[control.$name] = control;
20283             }
20284
20285             control.$$parentForm = form;
20286           };
20287
20288           // Private API: rename a form control
20289           form.$$renameControl = function(control, newName) {
20290             var oldName = control.$name;
20291
20292             if (form[oldName] === control) {
20293               delete form[oldName];
20294             }
20295             form[newName] = control;
20296             control.$name = newName;
20297           };
20298
20299           /**
20300            * @ngdoc method
20301            * @name form.FormController#$removeControl
20302            * @param {object} control control object, either a {@link form.FormController} or an
20303            * {@link ngModel.NgModelController}
20304            *
20305            * @description
20306            * Deregister a control from the form.
20307            *
20308            * Input elements using ngModelController do this automatically when they are destroyed.
20309            *
20310            * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
20311            * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
20312            * different from case to case. For example, removing the only `$dirty` control from a form may or
20313            * may not mean that the form is still `$dirty`.
20314            */
20315           form.$removeControl = function(control) {
20316             if (control.$name && form[control.$name] === control) {
20317               delete form[control.$name];
20318             }
20319             forEach(form.$pending, function(value, name) {
20320               form.$setValidity(name, null, control);
20321             });
20322             forEach(form.$error, function(value, name) {
20323               form.$setValidity(name, null, control);
20324             });
20325             forEach(form.$$success, function(value, name) {
20326               form.$setValidity(name, null, control);
20327             });
20328
20329             arrayRemove(controls, control);
20330             control.$$parentForm = nullFormCtrl;
20331           };
20332
20333
20334           /**
20335            * @ngdoc method
20336            * @name form.FormController#$setValidity
20337            *
20338            * @description
20339            * Sets the validity of a form control.
20340            *
20341            * This method will also propagate to parent forms.
20342            */
20343           addSetValidityMethod({
20344             ctrl: this,
20345             $element: element,
20346             set: function(object, property, controller) {
20347               var list = object[property];
20348               if (!list) {
20349                 object[property] = [controller];
20350               } else {
20351                 var index = list.indexOf(controller);
20352                 if (index === -1) {
20353                   list.push(controller);
20354                 }
20355               }
20356             },
20357             unset: function(object, property, controller) {
20358               var list = object[property];
20359               if (!list) {
20360                 return;
20361               }
20362               arrayRemove(list, controller);
20363               if (list.length === 0) {
20364                 delete object[property];
20365               }
20366             },
20367             $animate: $animate
20368           });
20369
20370           /**
20371            * @ngdoc method
20372            * @name form.FormController#$setDirty
20373            *
20374            * @description
20375            * Sets the form to a dirty state.
20376            *
20377            * This method can be called to add the 'ng-dirty' class and set the form to a dirty
20378            * state (ng-dirty class). This method will also propagate to parent forms.
20379            */
20380           form.$setDirty = function() {
20381             $animate.removeClass(element, PRISTINE_CLASS);
20382             $animate.addClass(element, DIRTY_CLASS);
20383             form.$dirty = true;
20384             form.$pristine = false;
20385             form.$$parentForm.$setDirty();
20386           };
20387
20388           /**
20389            * @ngdoc method
20390            * @name form.FormController#$setPristine
20391            *
20392            * @description
20393            * Sets the form to its pristine state.
20394            *
20395            * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
20396            * state (ng-pristine class). This method will also propagate to all the controls contained
20397            * in this form.
20398            *
20399            * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
20400            * saving or resetting it.
20401            */
20402           form.$setPristine = function() {
20403             $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
20404             form.$dirty = false;
20405             form.$pristine = true;
20406             form.$submitted = false;
20407             forEach(controls, function(control) {
20408               control.$setPristine();
20409             });
20410           };
20411
20412           /**
20413            * @ngdoc method
20414            * @name form.FormController#$setUntouched
20415            *
20416            * @description
20417            * Sets the form to its untouched state.
20418            *
20419            * This method can be called to remove the 'ng-touched' class and set the form controls to their
20420            * untouched state (ng-untouched class).
20421            *
20422            * Setting a form controls back to their untouched state is often useful when setting the form
20423            * back to its pristine state.
20424            */
20425           form.$setUntouched = function() {
20426             forEach(controls, function(control) {
20427               control.$setUntouched();
20428             });
20429           };
20430
20431           /**
20432            * @ngdoc method
20433            * @name form.FormController#$setSubmitted
20434            *
20435            * @description
20436            * Sets the form to its submitted state.
20437            */
20438           form.$setSubmitted = function() {
20439             $animate.addClass(element, SUBMITTED_CLASS);
20440             form.$submitted = true;
20441             form.$$parentForm.$setSubmitted();
20442           };
20443         }
20444
20445         /**
20446          * @ngdoc directive
20447          * @name ngForm
20448          * @restrict EAC
20449          *
20450          * @description
20451          * Nestable alias of {@link ng.directive:form `form`} directive. HTML
20452          * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
20453          * sub-group of controls needs to be determined.
20454          *
20455          * Note: the purpose of `ngForm` is to group controls,
20456          * but not to be a replacement for the `<form>` tag with all of its capabilities
20457          * (e.g. posting to the server, ...).
20458          *
20459          * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
20460          *                       related scope, under this name.
20461          *
20462          */
20463
20464          /**
20465          * @ngdoc directive
20466          * @name form
20467          * @restrict E
20468          *
20469          * @description
20470          * Directive that instantiates
20471          * {@link form.FormController FormController}.
20472          *
20473          * If the `name` attribute is specified, the form controller is published onto the current scope under
20474          * this name.
20475          *
20476          * # Alias: {@link ng.directive:ngForm `ngForm`}
20477          *
20478          * In Angular, forms can be nested. This means that the outer form is valid when all of the child
20479          * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
20480          * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
20481          * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
20482          * using Angular validation directives in forms that are dynamically generated using the
20483          * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
20484          * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
20485          * `ngForm` directive and nest these in an outer `form` element.
20486          *
20487          *
20488          * # CSS classes
20489          *  - `ng-valid` is set if the form is valid.
20490          *  - `ng-invalid` is set if the form is invalid.
20491          *  - `ng-pending` is set if the form is pending.
20492          *  - `ng-pristine` is set if the form is pristine.
20493          *  - `ng-dirty` is set if the form is dirty.
20494          *  - `ng-submitted` is set if the form was submitted.
20495          *
20496          * Keep in mind that ngAnimate can detect each of these classes when added and removed.
20497          *
20498          *
20499          * # Submitting a form and preventing the default action
20500          *
20501          * Since the role of forms in client-side Angular applications is different than in classical
20502          * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
20503          * page reload that sends the data to the server. Instead some javascript logic should be triggered
20504          * to handle the form submission in an application-specific way.
20505          *
20506          * For this reason, Angular prevents the default action (form submission to the server) unless the
20507          * `<form>` element has an `action` attribute specified.
20508          *
20509          * You can use one of the following two ways to specify what javascript method should be called when
20510          * a form is submitted:
20511          *
20512          * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
20513          * - {@link ng.directive:ngClick ngClick} directive on the first
20514           *  button or input field of type submit (input[type=submit])
20515          *
20516          * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
20517          * or {@link ng.directive:ngClick ngClick} directives.
20518          * This is because of the following form submission rules in the HTML specification:
20519          *
20520          * - If a form has only one input field then hitting enter in this field triggers form submit
20521          * (`ngSubmit`)
20522          * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
20523          * doesn't trigger submit
20524          * - if a form has one or more input fields and one or more buttons or input[type=submit] then
20525          * hitting enter in any of the input fields will trigger the click handler on the *first* button or
20526          * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
20527          *
20528          * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
20529          * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
20530          * to have access to the updated model.
20531          *
20532          * ## Animation Hooks
20533          *
20534          * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
20535          * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
20536          * other validations that are performed within the form. Animations in ngForm are similar to how
20537          * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
20538          * as JS animations.
20539          *
20540          * The following example shows a simple way to utilize CSS transitions to style a form element
20541          * that has been rendered as invalid after it has been validated:
20542          *
20543          * <pre>
20544          * //be sure to include ngAnimate as a module to hook into more
20545          * //advanced animations
20546          * .my-form {
20547          *   transition:0.5s linear all;
20548          *   background: white;
20549          * }
20550          * .my-form.ng-invalid {
20551          *   background: red;
20552          *   color:white;
20553          * }
20554          * </pre>
20555          *
20556          * @example
20557             <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
20558               <file name="index.html">
20559                <script>
20560                  angular.module('formExample', [])
20561                    .controller('FormController', ['$scope', function($scope) {
20562                      $scope.userType = 'guest';
20563                    }]);
20564                </script>
20565                <style>
20566                 .my-form {
20567                   transition:all linear 0.5s;
20568                   background: transparent;
20569                 }
20570                 .my-form.ng-invalid {
20571                   background: red;
20572                 }
20573                </style>
20574                <form name="myForm" ng-controller="FormController" class="my-form">
20575                  userType: <input name="input" ng-model="userType" required>
20576                  <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
20577                  <code>userType = {{userType}}</code><br>
20578                  <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
20579                  <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
20580                  <code>myForm.$valid = {{myForm.$valid}}</code><br>
20581                  <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
20582                 </form>
20583               </file>
20584               <file name="protractor.js" type="protractor">
20585                 it('should initialize to model', function() {
20586                   var userType = element(by.binding('userType'));
20587                   var valid = element(by.binding('myForm.input.$valid'));
20588
20589                   expect(userType.getText()).toContain('guest');
20590                   expect(valid.getText()).toContain('true');
20591                 });
20592
20593                 it('should be invalid if empty', function() {
20594                   var userType = element(by.binding('userType'));
20595                   var valid = element(by.binding('myForm.input.$valid'));
20596                   var userInput = element(by.model('userType'));
20597
20598                   userInput.clear();
20599                   userInput.sendKeys('');
20600
20601                   expect(userType.getText()).toEqual('userType =');
20602                   expect(valid.getText()).toContain('false');
20603                 });
20604               </file>
20605             </example>
20606          *
20607          * @param {string=} name Name of the form. If specified, the form controller will be published into
20608          *                       related scope, under this name.
20609          */
20610         var formDirectiveFactory = function(isNgForm) {
20611           return ['$timeout', '$parse', function($timeout, $parse) {
20612             var formDirective = {
20613               name: 'form',
20614               restrict: isNgForm ? 'EAC' : 'E',
20615               require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
20616               controller: FormController,
20617               compile: function ngFormCompile(formElement, attr) {
20618                 // Setup initial state of the control
20619                 formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
20620
20621                 var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
20622
20623                 return {
20624                   pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
20625                     var controller = ctrls[0];
20626
20627                     // if `action` attr is not present on the form, prevent the default action (submission)
20628                     if (!('action' in attr)) {
20629                       // we can't use jq events because if a form is destroyed during submission the default
20630                       // action is not prevented. see #1238
20631                       //
20632                       // IE 9 is not affected because it doesn't fire a submit event and try to do a full
20633                       // page reload if the form was destroyed by submission of the form via a click handler
20634                       // on a button in the form. Looks like an IE9 specific bug.
20635                       var handleFormSubmission = function(event) {
20636                         scope.$apply(function() {
20637                           controller.$commitViewValue();
20638                           controller.$setSubmitted();
20639                         });
20640
20641                         event.preventDefault();
20642                       };
20643
20644                       addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20645
20646                       // unregister the preventDefault listener so that we don't not leak memory but in a
20647                       // way that will achieve the prevention of the default action.
20648                       formElement.on('$destroy', function() {
20649                         $timeout(function() {
20650                           removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20651                         }, 0, false);
20652                       });
20653                     }
20654
20655                     var parentFormCtrl = ctrls[1] || controller.$$parentForm;
20656                     parentFormCtrl.$addControl(controller);
20657
20658                     var setter = nameAttr ? getSetter(controller.$name) : noop;
20659
20660                     if (nameAttr) {
20661                       setter(scope, controller);
20662                       attr.$observe(nameAttr, function(newValue) {
20663                         if (controller.$name === newValue) return;
20664                         setter(scope, undefined);
20665                         controller.$$parentForm.$$renameControl(controller, newValue);
20666                         setter = getSetter(controller.$name);
20667                         setter(scope, controller);
20668                       });
20669                     }
20670                     formElement.on('$destroy', function() {
20671                       controller.$$parentForm.$removeControl(controller);
20672                       setter(scope, undefined);
20673                       extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
20674                     });
20675                   }
20676                 };
20677               }
20678             };
20679
20680             return formDirective;
20681
20682             function getSetter(expression) {
20683               if (expression === '') {
20684                 //create an assignable expression, so forms with an empty name can be renamed later
20685                 return $parse('this[""]').assign;
20686               }
20687               return $parse(expression).assign || noop;
20688             }
20689           }];
20690         };
20691
20692         var formDirective = formDirectiveFactory();
20693         var ngFormDirective = formDirectiveFactory(true);
20694
20695         /* global VALID_CLASS: false,
20696           INVALID_CLASS: false,
20697           PRISTINE_CLASS: false,
20698           DIRTY_CLASS: false,
20699           UNTOUCHED_CLASS: false,
20700           TOUCHED_CLASS: false,
20701           ngModelMinErr: false,
20702         */
20703
20704         // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
20705         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)/;
20706         // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
20707         var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/;
20708         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;
20709         var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
20710         var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
20711         var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20712         var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
20713         var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
20714         var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20715
20716         var inputType = {
20717
20718           /**
20719            * @ngdoc input
20720            * @name input[text]
20721            *
20722            * @description
20723            * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
20724            *
20725            *
20726            * @param {string} ngModel Assignable angular expression to data-bind to.
20727            * @param {string=} name Property name of the form under which the control is published.
20728            * @param {string=} required Adds `required` validation error key if the value is not entered.
20729            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20730            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20731            *    `required` when you want to data-bind to the `required` attribute.
20732            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20733            *    minlength.
20734            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20735            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
20736            *    any length.
20737            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
20738            *    that contains the regular expression body that will be converted to a regular expression
20739            *    as in the ngPattern directive.
20740            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
20741            *    a RegExp found by evaluating the Angular expression given in the attribute value.
20742            *    If the expression evaluates to a RegExp object, then this is used directly.
20743            *    If the expression evaluates to a string, then it will be converted to a RegExp
20744            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
20745            *    `new RegExp('^abc$')`.<br />
20746            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
20747            *    start at the index of the last search's match, thus not taking the whole input value into
20748            *    account.
20749            * @param {string=} ngChange Angular expression to be executed when input changes due to user
20750            *    interaction with the input element.
20751            * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20752            *    This parameter is ignored for input[type=password] controls, which will never trim the
20753            *    input.
20754            *
20755            * @example
20756               <example name="text-input-directive" module="textInputExample">
20757                 <file name="index.html">
20758                  <script>
20759                    angular.module('textInputExample', [])
20760                      .controller('ExampleController', ['$scope', function($scope) {
20761                        $scope.example = {
20762                          text: 'guest',
20763                          word: /^\s*\w*\s*$/
20764                        };
20765                      }]);
20766                  </script>
20767                  <form name="myForm" ng-controller="ExampleController">
20768                    <label>Single word:
20769                      <input type="text" name="input" ng-model="example.text"
20770                             ng-pattern="example.word" required ng-trim="false">
20771                    </label>
20772                    <div role="alert">
20773                      <span class="error" ng-show="myForm.input.$error.required">
20774                        Required!</span>
20775                      <span class="error" ng-show="myForm.input.$error.pattern">
20776                        Single word only!</span>
20777                    </div>
20778                    <tt>text = {{example.text}}</tt><br/>
20779                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20780                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20781                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20782                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20783                   </form>
20784                 </file>
20785                 <file name="protractor.js" type="protractor">
20786                   var text = element(by.binding('example.text'));
20787                   var valid = element(by.binding('myForm.input.$valid'));
20788                   var input = element(by.model('example.text'));
20789
20790                   it('should initialize to model', function() {
20791                     expect(text.getText()).toContain('guest');
20792                     expect(valid.getText()).toContain('true');
20793                   });
20794
20795                   it('should be invalid if empty', function() {
20796                     input.clear();
20797                     input.sendKeys('');
20798
20799                     expect(text.getText()).toEqual('text =');
20800                     expect(valid.getText()).toContain('false');
20801                   });
20802
20803                   it('should be invalid if multi word', function() {
20804                     input.clear();
20805                     input.sendKeys('hello world');
20806
20807                     expect(valid.getText()).toContain('false');
20808                   });
20809                 </file>
20810               </example>
20811            */
20812           'text': textInputType,
20813
20814             /**
20815              * @ngdoc input
20816              * @name input[date]
20817              *
20818              * @description
20819              * Input with date validation and transformation. In browsers that do not yet support
20820              * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
20821              * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
20822              * modern browsers do not yet support this input type, it is important to provide cues to users on the
20823              * expected input format via a placeholder or label.
20824              *
20825              * The model must always be a Date object, otherwise Angular will throw an error.
20826              * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20827              *
20828              * The timezone to be used to read/write the `Date` instance in the model can be defined using
20829              * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20830              *
20831              * @param {string} ngModel Assignable angular expression to data-bind to.
20832              * @param {string=} name Property name of the form under which the control is published.
20833              * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
20834              *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
20835              *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
20836              *   constraint validation.
20837              * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
20838              *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
20839              *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
20840              *   constraint validation.
20841              * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
20842              *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20843              * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
20844              *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20845              * @param {string=} required Sets `required` validation error key if the value is not entered.
20846              * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20847              *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20848              *    `required` when you want to data-bind to the `required` attribute.
20849              * @param {string=} ngChange Angular expression to be executed when input changes due to user
20850              *    interaction with the input element.
20851              *
20852              * @example
20853              <example name="date-input-directive" module="dateInputExample">
20854              <file name="index.html">
20855                <script>
20856                   angular.module('dateInputExample', [])
20857                     .controller('DateController', ['$scope', function($scope) {
20858                       $scope.example = {
20859                         value: new Date(2013, 9, 22)
20860                       };
20861                     }]);
20862                </script>
20863                <form name="myForm" ng-controller="DateController as dateCtrl">
20864                   <label for="exampleInput">Pick a date in 2013:</label>
20865                   <input type="date" id="exampleInput" name="input" ng-model="example.value"
20866                       placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
20867                   <div role="alert">
20868                     <span class="error" ng-show="myForm.input.$error.required">
20869                         Required!</span>
20870                     <span class="error" ng-show="myForm.input.$error.date">
20871                         Not a valid date!</span>
20872                    </div>
20873                    <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
20874                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20875                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20876                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20877                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20878                </form>
20879              </file>
20880              <file name="protractor.js" type="protractor">
20881                 var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
20882                 var valid = element(by.binding('myForm.input.$valid'));
20883                 var input = element(by.model('example.value'));
20884
20885                 // currently protractor/webdriver does not support
20886                 // sending keys to all known HTML5 input controls
20887                 // for various browsers (see https://github.com/angular/protractor/issues/562).
20888                 function setInput(val) {
20889                   // set the value of the element and force validation.
20890                   var scr = "var ipt = document.getElementById('exampleInput'); " +
20891                   "ipt.value = '" + val + "';" +
20892                   "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20893                   browser.executeScript(scr);
20894                 }
20895
20896                 it('should initialize to model', function() {
20897                   expect(value.getText()).toContain('2013-10-22');
20898                   expect(valid.getText()).toContain('myForm.input.$valid = true');
20899                 });
20900
20901                 it('should be invalid if empty', function() {
20902                   setInput('');
20903                   expect(value.getText()).toEqual('value =');
20904                   expect(valid.getText()).toContain('myForm.input.$valid = false');
20905                 });
20906
20907                 it('should be invalid if over max', function() {
20908                   setInput('2015-01-01');
20909                   expect(value.getText()).toContain('');
20910                   expect(valid.getText()).toContain('myForm.input.$valid = false');
20911                 });
20912              </file>
20913              </example>
20914              */
20915           'date': createDateInputType('date', DATE_REGEXP,
20916                  createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
20917                  'yyyy-MM-dd'),
20918
20919            /**
20920             * @ngdoc input
20921             * @name input[datetime-local]
20922             *
20923             * @description
20924             * Input with datetime validation and transformation. In browsers that do not yet support
20925             * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20926             * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
20927             *
20928             * The model must always be a Date object, otherwise Angular will throw an error.
20929             * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20930             *
20931             * The timezone to be used to read/write the `Date` instance in the model can be defined using
20932             * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20933             *
20934             * @param {string} ngModel Assignable angular expression to data-bind to.
20935             * @param {string=} name Property name of the form under which the control is published.
20936             * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
20937             *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
20938             *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
20939             *   Note that `min` will also add native HTML5 constraint validation.
20940             * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
20941             *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
20942             *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
20943             *   Note that `max` will also add native HTML5 constraint validation.
20944             * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
20945             *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20946             * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
20947             *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20948             * @param {string=} required Sets `required` validation error key if the value is not entered.
20949             * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20950             *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20951             *    `required` when you want to data-bind to the `required` attribute.
20952             * @param {string=} ngChange Angular expression to be executed when input changes due to user
20953             *    interaction with the input element.
20954             *
20955             * @example
20956             <example name="datetimelocal-input-directive" module="dateExample">
20957             <file name="index.html">
20958               <script>
20959                 angular.module('dateExample', [])
20960                   .controller('DateController', ['$scope', function($scope) {
20961                     $scope.example = {
20962                       value: new Date(2010, 11, 28, 14, 57)
20963                     };
20964                   }]);
20965               </script>
20966               <form name="myForm" ng-controller="DateController as dateCtrl">
20967                 <label for="exampleInput">Pick a date between in 2013:</label>
20968                 <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
20969                     placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
20970                 <div role="alert">
20971                   <span class="error" ng-show="myForm.input.$error.required">
20972                       Required!</span>
20973                   <span class="error" ng-show="myForm.input.$error.datetimelocal">
20974                       Not a valid date!</span>
20975                 </div>
20976                 <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
20977                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20978                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20979                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20980                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20981               </form>
20982             </file>
20983             <file name="protractor.js" type="protractor">
20984               var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
20985               var valid = element(by.binding('myForm.input.$valid'));
20986               var input = element(by.model('example.value'));
20987
20988               // currently protractor/webdriver does not support
20989               // sending keys to all known HTML5 input controls
20990               // for various browsers (https://github.com/angular/protractor/issues/562).
20991               function setInput(val) {
20992                 // set the value of the element and force validation.
20993                 var scr = "var ipt = document.getElementById('exampleInput'); " +
20994                 "ipt.value = '" + val + "';" +
20995                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20996                 browser.executeScript(scr);
20997               }
20998
20999               it('should initialize to model', function() {
21000                 expect(value.getText()).toContain('2010-12-28T14:57:00');
21001                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21002               });
21003
21004               it('should be invalid if empty', function() {
21005                 setInput('');
21006                 expect(value.getText()).toEqual('value =');
21007                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21008               });
21009
21010               it('should be invalid if over max', function() {
21011                 setInput('2015-01-01T23:59:00');
21012                 expect(value.getText()).toContain('');
21013                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21014               });
21015             </file>
21016             </example>
21017             */
21018           'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
21019               createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
21020               'yyyy-MM-ddTHH:mm:ss.sss'),
21021
21022           /**
21023            * @ngdoc input
21024            * @name input[time]
21025            *
21026            * @description
21027            * Input with time validation and transformation. In browsers that do not yet support
21028            * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21029            * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
21030            * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
21031            *
21032            * The model must always be a Date object, otherwise Angular will throw an error.
21033            * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21034            *
21035            * The timezone to be used to read/write the `Date` instance in the model can be defined using
21036            * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21037            *
21038            * @param {string} ngModel Assignable angular expression to data-bind to.
21039            * @param {string=} name Property name of the form under which the control is published.
21040            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21041            *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
21042            *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
21043            *   native HTML5 constraint validation.
21044            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21045            *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
21046            *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
21047            *   native HTML5 constraint validation.
21048            * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
21049            *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21050            * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
21051            *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21052            * @param {string=} required Sets `required` validation error key if the value is not entered.
21053            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21054            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21055            *    `required` when you want to data-bind to the `required` attribute.
21056            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21057            *    interaction with the input element.
21058            *
21059            * @example
21060            <example name="time-input-directive" module="timeExample">
21061            <file name="index.html">
21062              <script>
21063               angular.module('timeExample', [])
21064                 .controller('DateController', ['$scope', function($scope) {
21065                   $scope.example = {
21066                     value: new Date(1970, 0, 1, 14, 57, 0)
21067                   };
21068                 }]);
21069              </script>
21070              <form name="myForm" ng-controller="DateController as dateCtrl">
21071                 <label for="exampleInput">Pick a between 8am and 5pm:</label>
21072                 <input type="time" id="exampleInput" name="input" ng-model="example.value"
21073                     placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
21074                 <div role="alert">
21075                   <span class="error" ng-show="myForm.input.$error.required">
21076                       Required!</span>
21077                   <span class="error" ng-show="myForm.input.$error.time">
21078                       Not a valid date!</span>
21079                 </div>
21080                 <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
21081                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21082                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21083                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21084                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21085              </form>
21086            </file>
21087            <file name="protractor.js" type="protractor">
21088               var value = element(by.binding('example.value | date: "HH:mm:ss"'));
21089               var valid = element(by.binding('myForm.input.$valid'));
21090               var input = element(by.model('example.value'));
21091
21092               // currently protractor/webdriver does not support
21093               // sending keys to all known HTML5 input controls
21094               // for various browsers (https://github.com/angular/protractor/issues/562).
21095               function setInput(val) {
21096                 // set the value of the element and force validation.
21097                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21098                 "ipt.value = '" + val + "';" +
21099                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21100                 browser.executeScript(scr);
21101               }
21102
21103               it('should initialize to model', function() {
21104                 expect(value.getText()).toContain('14:57:00');
21105                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21106               });
21107
21108               it('should be invalid if empty', function() {
21109                 setInput('');
21110                 expect(value.getText()).toEqual('value =');
21111                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21112               });
21113
21114               it('should be invalid if over max', function() {
21115                 setInput('23:59:00');
21116                 expect(value.getText()).toContain('');
21117                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21118               });
21119            </file>
21120            </example>
21121            */
21122           'time': createDateInputType('time', TIME_REGEXP,
21123               createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
21124              'HH:mm:ss.sss'),
21125
21126            /**
21127             * @ngdoc input
21128             * @name input[week]
21129             *
21130             * @description
21131             * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
21132             * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21133             * week format (yyyy-W##), for example: `2013-W02`.
21134             *
21135             * The model must always be a Date object, otherwise Angular will throw an error.
21136             * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21137             *
21138             * The timezone to be used to read/write the `Date` instance in the model can be defined using
21139             * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21140             *
21141             * @param {string} ngModel Assignable angular expression to data-bind to.
21142             * @param {string=} name Property name of the form under which the control is published.
21143             * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21144             *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
21145             *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
21146             *   native HTML5 constraint validation.
21147             * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21148             *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
21149             *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
21150             *   native HTML5 constraint validation.
21151             * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
21152             *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21153             * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
21154             *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21155             * @param {string=} required Sets `required` validation error key if the value is not entered.
21156             * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21157             *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21158             *    `required` when you want to data-bind to the `required` attribute.
21159             * @param {string=} ngChange Angular expression to be executed when input changes due to user
21160             *    interaction with the input element.
21161             *
21162             * @example
21163             <example name="week-input-directive" module="weekExample">
21164             <file name="index.html">
21165               <script>
21166               angular.module('weekExample', [])
21167                 .controller('DateController', ['$scope', function($scope) {
21168                   $scope.example = {
21169                     value: new Date(2013, 0, 3)
21170                   };
21171                 }]);
21172               </script>
21173               <form name="myForm" ng-controller="DateController as dateCtrl">
21174                 <label>Pick a date between in 2013:
21175                   <input id="exampleInput" type="week" name="input" ng-model="example.value"
21176                          placeholder="YYYY-W##" min="2012-W32"
21177                          max="2013-W52" required />
21178                 </label>
21179                 <div role="alert">
21180                   <span class="error" ng-show="myForm.input.$error.required">
21181                       Required!</span>
21182                   <span class="error" ng-show="myForm.input.$error.week">
21183                       Not a valid date!</span>
21184                 </div>
21185                 <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
21186                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21187                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21188                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21189                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21190               </form>
21191             </file>
21192             <file name="protractor.js" type="protractor">
21193               var value = element(by.binding('example.value | date: "yyyy-Www"'));
21194               var valid = element(by.binding('myForm.input.$valid'));
21195               var input = element(by.model('example.value'));
21196
21197               // currently protractor/webdriver does not support
21198               // sending keys to all known HTML5 input controls
21199               // for various browsers (https://github.com/angular/protractor/issues/562).
21200               function setInput(val) {
21201                 // set the value of the element and force validation.
21202                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21203                 "ipt.value = '" + val + "';" +
21204                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21205                 browser.executeScript(scr);
21206               }
21207
21208               it('should initialize to model', function() {
21209                 expect(value.getText()).toContain('2013-W01');
21210                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21211               });
21212
21213               it('should be invalid if empty', function() {
21214                 setInput('');
21215                 expect(value.getText()).toEqual('value =');
21216                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21217               });
21218
21219               it('should be invalid if over max', function() {
21220                 setInput('2015-W01');
21221                 expect(value.getText()).toContain('');
21222                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21223               });
21224             </file>
21225             </example>
21226             */
21227           'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
21228
21229           /**
21230            * @ngdoc input
21231            * @name input[month]
21232            *
21233            * @description
21234            * Input with month validation and transformation. In browsers that do not yet support
21235            * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21236            * month format (yyyy-MM), for example: `2009-01`.
21237            *
21238            * The model must always be a Date object, otherwise Angular will throw an error.
21239            * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21240            * If the model is not set to the first of the month, the next view to model update will set it
21241            * to the first of the month.
21242            *
21243            * The timezone to be used to read/write the `Date` instance in the model can be defined using
21244            * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21245            *
21246            * @param {string} ngModel Assignable angular expression to data-bind to.
21247            * @param {string=} name Property name of the form under which the control is published.
21248            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21249            *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
21250            *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
21251            *   native HTML5 constraint validation.
21252            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21253            *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
21254            *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
21255            *   native HTML5 constraint validation.
21256            * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
21257            *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21258            * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
21259            *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21260
21261            * @param {string=} required Sets `required` validation error key if the value is not entered.
21262            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21263            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21264            *    `required` when you want to data-bind to the `required` attribute.
21265            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21266            *    interaction with the input element.
21267            *
21268            * @example
21269            <example name="month-input-directive" module="monthExample">
21270            <file name="index.html">
21271              <script>
21272               angular.module('monthExample', [])
21273                 .controller('DateController', ['$scope', function($scope) {
21274                   $scope.example = {
21275                     value: new Date(2013, 9, 1)
21276                   };
21277                 }]);
21278              </script>
21279              <form name="myForm" ng-controller="DateController as dateCtrl">
21280                <label for="exampleInput">Pick a month in 2013:</label>
21281                <input id="exampleInput" type="month" name="input" ng-model="example.value"
21282                   placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
21283                <div role="alert">
21284                  <span class="error" ng-show="myForm.input.$error.required">
21285                     Required!</span>
21286                  <span class="error" ng-show="myForm.input.$error.month">
21287                     Not a valid month!</span>
21288                </div>
21289                <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
21290                <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21291                <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21292                <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21293                <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21294              </form>
21295            </file>
21296            <file name="protractor.js" type="protractor">
21297               var value = element(by.binding('example.value | date: "yyyy-MM"'));
21298               var valid = element(by.binding('myForm.input.$valid'));
21299               var input = element(by.model('example.value'));
21300
21301               // currently protractor/webdriver does not support
21302               // sending keys to all known HTML5 input controls
21303               // for various browsers (https://github.com/angular/protractor/issues/562).
21304               function setInput(val) {
21305                 // set the value of the element and force validation.
21306                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21307                 "ipt.value = '" + val + "';" +
21308                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21309                 browser.executeScript(scr);
21310               }
21311
21312               it('should initialize to model', function() {
21313                 expect(value.getText()).toContain('2013-10');
21314                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21315               });
21316
21317               it('should be invalid if empty', function() {
21318                 setInput('');
21319                 expect(value.getText()).toEqual('value =');
21320                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21321               });
21322
21323               it('should be invalid if over max', function() {
21324                 setInput('2015-01');
21325                 expect(value.getText()).toContain('');
21326                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21327               });
21328            </file>
21329            </example>
21330            */
21331           'month': createDateInputType('month', MONTH_REGEXP,
21332              createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
21333              'yyyy-MM'),
21334
21335           /**
21336            * @ngdoc input
21337            * @name input[number]
21338            *
21339            * @description
21340            * Text input with number validation and transformation. Sets the `number` validation
21341            * error if not a valid number.
21342            *
21343            * <div class="alert alert-warning">
21344            * The model must always be of type `number` otherwise Angular will throw an error.
21345            * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
21346            * error docs for more information and an example of how to convert your model if necessary.
21347            * </div>
21348            *
21349            * ## Issues with HTML5 constraint validation
21350            *
21351            * In browsers that follow the
21352            * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
21353            * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
21354            * If a non-number is entered in the input, the browser will report the value as an empty string,
21355            * which means the view / model values in `ngModel` and subsequently the scope value
21356            * will also be an empty string.
21357            *
21358            *
21359            * @param {string} ngModel Assignable angular expression to data-bind to.
21360            * @param {string=} name Property name of the form under which the control is published.
21361            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21362            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21363            * @param {string=} required Sets `required` validation error key if the value is not entered.
21364            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21365            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21366            *    `required` when you want to data-bind to the `required` attribute.
21367            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21368            *    minlength.
21369            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21370            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21371            *    any length.
21372            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21373            *    that contains the regular expression body that will be converted to a regular expression
21374            *    as in the ngPattern directive.
21375            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21376            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21377            *    If the expression evaluates to a RegExp object, then this is used directly.
21378            *    If the expression evaluates to a string, then it will be converted to a RegExp
21379            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21380            *    `new RegExp('^abc$')`.<br />
21381            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21382            *    start at the index of the last search's match, thus not taking the whole input value into
21383            *    account.
21384            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21385            *    interaction with the input element.
21386            *
21387            * @example
21388               <example name="number-input-directive" module="numberExample">
21389                 <file name="index.html">
21390                  <script>
21391                    angular.module('numberExample', [])
21392                      .controller('ExampleController', ['$scope', function($scope) {
21393                        $scope.example = {
21394                          value: 12
21395                        };
21396                      }]);
21397                  </script>
21398                  <form name="myForm" ng-controller="ExampleController">
21399                    <label>Number:
21400                      <input type="number" name="input" ng-model="example.value"
21401                             min="0" max="99" required>
21402                   </label>
21403                    <div role="alert">
21404                      <span class="error" ng-show="myForm.input.$error.required">
21405                        Required!</span>
21406                      <span class="error" ng-show="myForm.input.$error.number">
21407                        Not valid number!</span>
21408                    </div>
21409                    <tt>value = {{example.value}}</tt><br/>
21410                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21411                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21412                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21413                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21414                   </form>
21415                 </file>
21416                 <file name="protractor.js" type="protractor">
21417                   var value = element(by.binding('example.value'));
21418                   var valid = element(by.binding('myForm.input.$valid'));
21419                   var input = element(by.model('example.value'));
21420
21421                   it('should initialize to model', function() {
21422                     expect(value.getText()).toContain('12');
21423                     expect(valid.getText()).toContain('true');
21424                   });
21425
21426                   it('should be invalid if empty', function() {
21427                     input.clear();
21428                     input.sendKeys('');
21429                     expect(value.getText()).toEqual('value =');
21430                     expect(valid.getText()).toContain('false');
21431                   });
21432
21433                   it('should be invalid if over max', function() {
21434                     input.clear();
21435                     input.sendKeys('123');
21436                     expect(value.getText()).toEqual('value =');
21437                     expect(valid.getText()).toContain('false');
21438                   });
21439                 </file>
21440               </example>
21441            */
21442           'number': numberInputType,
21443
21444
21445           /**
21446            * @ngdoc input
21447            * @name input[url]
21448            *
21449            * @description
21450            * Text input with URL validation. Sets the `url` validation error key if the content is not a
21451            * valid URL.
21452            *
21453            * <div class="alert alert-warning">
21454            * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
21455            * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
21456            * the built-in validators (see the {@link guide/forms Forms guide})
21457            * </div>
21458            *
21459            * @param {string} ngModel Assignable angular expression to data-bind to.
21460            * @param {string=} name Property name of the form under which the control is published.
21461            * @param {string=} required Sets `required` validation error key if the value is not entered.
21462            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21463            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21464            *    `required` when you want to data-bind to the `required` attribute.
21465            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21466            *    minlength.
21467            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21468            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21469            *    any length.
21470            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21471            *    that contains the regular expression body that will be converted to a regular expression
21472            *    as in the ngPattern directive.
21473            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21474            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21475            *    If the expression evaluates to a RegExp object, then this is used directly.
21476            *    If the expression evaluates to a string, then it will be converted to a RegExp
21477            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21478            *    `new RegExp('^abc$')`.<br />
21479            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21480            *    start at the index of the last search's match, thus not taking the whole input value into
21481            *    account.
21482            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21483            *    interaction with the input element.
21484            *
21485            * @example
21486               <example name="url-input-directive" module="urlExample">
21487                 <file name="index.html">
21488                  <script>
21489                    angular.module('urlExample', [])
21490                      .controller('ExampleController', ['$scope', function($scope) {
21491                        $scope.url = {
21492                          text: 'http://google.com'
21493                        };
21494                      }]);
21495                  </script>
21496                  <form name="myForm" ng-controller="ExampleController">
21497                    <label>URL:
21498                      <input type="url" name="input" ng-model="url.text" required>
21499                    <label>
21500                    <div role="alert">
21501                      <span class="error" ng-show="myForm.input.$error.required">
21502                        Required!</span>
21503                      <span class="error" ng-show="myForm.input.$error.url">
21504                        Not valid url!</span>
21505                    </div>
21506                    <tt>text = {{url.text}}</tt><br/>
21507                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21508                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21509                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21510                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21511                    <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
21512                   </form>
21513                 </file>
21514                 <file name="protractor.js" type="protractor">
21515                   var text = element(by.binding('url.text'));
21516                   var valid = element(by.binding('myForm.input.$valid'));
21517                   var input = element(by.model('url.text'));
21518
21519                   it('should initialize to model', function() {
21520                     expect(text.getText()).toContain('http://google.com');
21521                     expect(valid.getText()).toContain('true');
21522                   });
21523
21524                   it('should be invalid if empty', function() {
21525                     input.clear();
21526                     input.sendKeys('');
21527
21528                     expect(text.getText()).toEqual('text =');
21529                     expect(valid.getText()).toContain('false');
21530                   });
21531
21532                   it('should be invalid if not url', function() {
21533                     input.clear();
21534                     input.sendKeys('box');
21535
21536                     expect(valid.getText()).toContain('false');
21537                   });
21538                 </file>
21539               </example>
21540            */
21541           'url': urlInputType,
21542
21543
21544           /**
21545            * @ngdoc input
21546            * @name input[email]
21547            *
21548            * @description
21549            * Text input with email validation. Sets the `email` validation error key if not a valid email
21550            * address.
21551            *
21552            * <div class="alert alert-warning">
21553            * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
21554            * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
21555            * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
21556            * </div>
21557            *
21558            * @param {string} ngModel Assignable angular expression to data-bind to.
21559            * @param {string=} name Property name of the form under which the control is published.
21560            * @param {string=} required Sets `required` validation error key if the value is not entered.
21561            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21562            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21563            *    `required` when you want to data-bind to the `required` attribute.
21564            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21565            *    minlength.
21566            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21567            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21568            *    any length.
21569            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21570            *    that contains the regular expression body that will be converted to a regular expression
21571            *    as in the ngPattern directive.
21572            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21573            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21574            *    If the expression evaluates to a RegExp object, then this is used directly.
21575            *    If the expression evaluates to a string, then it will be converted to a RegExp
21576            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21577            *    `new RegExp('^abc$')`.<br />
21578            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21579            *    start at the index of the last search's match, thus not taking the whole input value into
21580            *    account.
21581            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21582            *    interaction with the input element.
21583            *
21584            * @example
21585               <example name="email-input-directive" module="emailExample">
21586                 <file name="index.html">
21587                  <script>
21588                    angular.module('emailExample', [])
21589                      .controller('ExampleController', ['$scope', function($scope) {
21590                        $scope.email = {
21591                          text: 'me@example.com'
21592                        };
21593                      }]);
21594                  </script>
21595                    <form name="myForm" ng-controller="ExampleController">
21596                      <label>Email:
21597                        <input type="email" name="input" ng-model="email.text" required>
21598                      </label>
21599                      <div role="alert">
21600                        <span class="error" ng-show="myForm.input.$error.required">
21601                          Required!</span>
21602                        <span class="error" ng-show="myForm.input.$error.email">
21603                          Not valid email!</span>
21604                      </div>
21605                      <tt>text = {{email.text}}</tt><br/>
21606                      <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21607                      <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21608                      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21609                      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21610                      <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
21611                    </form>
21612                  </file>
21613                 <file name="protractor.js" type="protractor">
21614                   var text = element(by.binding('email.text'));
21615                   var valid = element(by.binding('myForm.input.$valid'));
21616                   var input = element(by.model('email.text'));
21617
21618                   it('should initialize to model', function() {
21619                     expect(text.getText()).toContain('me@example.com');
21620                     expect(valid.getText()).toContain('true');
21621                   });
21622
21623                   it('should be invalid if empty', function() {
21624                     input.clear();
21625                     input.sendKeys('');
21626                     expect(text.getText()).toEqual('text =');
21627                     expect(valid.getText()).toContain('false');
21628                   });
21629
21630                   it('should be invalid if not email', function() {
21631                     input.clear();
21632                     input.sendKeys('xxx');
21633
21634                     expect(valid.getText()).toContain('false');
21635                   });
21636                 </file>
21637               </example>
21638            */
21639           'email': emailInputType,
21640
21641
21642           /**
21643            * @ngdoc input
21644            * @name input[radio]
21645            *
21646            * @description
21647            * HTML radio button.
21648            *
21649            * @param {string} ngModel Assignable angular expression to data-bind to.
21650            * @param {string} value The value to which the `ngModel` expression should be set when selected.
21651            *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
21652            *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
21653            * @param {string=} name Property name of the form under which the control is published.
21654            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21655            *    interaction with the input element.
21656            * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
21657            *    is selected. Should be used instead of the `value` attribute if you need
21658            *    a non-string `ngModel` (`boolean`, `array`, ...).
21659            *
21660            * @example
21661               <example name="radio-input-directive" module="radioExample">
21662                 <file name="index.html">
21663                  <script>
21664                    angular.module('radioExample', [])
21665                      .controller('ExampleController', ['$scope', function($scope) {
21666                        $scope.color = {
21667                          name: 'blue'
21668                        };
21669                        $scope.specialValue = {
21670                          "id": "12345",
21671                          "value": "green"
21672                        };
21673                      }]);
21674                  </script>
21675                  <form name="myForm" ng-controller="ExampleController">
21676                    <label>
21677                      <input type="radio" ng-model="color.name" value="red">
21678                      Red
21679                    </label><br/>
21680                    <label>
21681                      <input type="radio" ng-model="color.name" ng-value="specialValue">
21682                      Green
21683                    </label><br/>
21684                    <label>
21685                      <input type="radio" ng-model="color.name" value="blue">
21686                      Blue
21687                    </label><br/>
21688                    <tt>color = {{color.name | json}}</tt><br/>
21689                   </form>
21690                   Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
21691                 </file>
21692                 <file name="protractor.js" type="protractor">
21693                   it('should change state', function() {
21694                     var color = element(by.binding('color.name'));
21695
21696                     expect(color.getText()).toContain('blue');
21697
21698                     element.all(by.model('color.name')).get(0).click();
21699
21700                     expect(color.getText()).toContain('red');
21701                   });
21702                 </file>
21703               </example>
21704            */
21705           'radio': radioInputType,
21706
21707
21708           /**
21709            * @ngdoc input
21710            * @name input[checkbox]
21711            *
21712            * @description
21713            * HTML checkbox.
21714            *
21715            * @param {string} ngModel Assignable angular expression to data-bind to.
21716            * @param {string=} name Property name of the form under which the control is published.
21717            * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
21718            * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
21719            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21720            *    interaction with the input element.
21721            *
21722            * @example
21723               <example name="checkbox-input-directive" module="checkboxExample">
21724                 <file name="index.html">
21725                  <script>
21726                    angular.module('checkboxExample', [])
21727                      .controller('ExampleController', ['$scope', function($scope) {
21728                        $scope.checkboxModel = {
21729                         value1 : true,
21730                         value2 : 'YES'
21731                       };
21732                      }]);
21733                  </script>
21734                  <form name="myForm" ng-controller="ExampleController">
21735                    <label>Value1:
21736                      <input type="checkbox" ng-model="checkboxModel.value1">
21737                    </label><br/>
21738                    <label>Value2:
21739                      <input type="checkbox" ng-model="checkboxModel.value2"
21740                             ng-true-value="'YES'" ng-false-value="'NO'">
21741                     </label><br/>
21742                    <tt>value1 = {{checkboxModel.value1}}</tt><br/>
21743                    <tt>value2 = {{checkboxModel.value2}}</tt><br/>
21744                   </form>
21745                 </file>
21746                 <file name="protractor.js" type="protractor">
21747                   it('should change state', function() {
21748                     var value1 = element(by.binding('checkboxModel.value1'));
21749                     var value2 = element(by.binding('checkboxModel.value2'));
21750
21751                     expect(value1.getText()).toContain('true');
21752                     expect(value2.getText()).toContain('YES');
21753
21754                     element(by.model('checkboxModel.value1')).click();
21755                     element(by.model('checkboxModel.value2')).click();
21756
21757                     expect(value1.getText()).toContain('false');
21758                     expect(value2.getText()).toContain('NO');
21759                   });
21760                 </file>
21761               </example>
21762            */
21763           'checkbox': checkboxInputType,
21764
21765           'hidden': noop,
21766           'button': noop,
21767           'submit': noop,
21768           'reset': noop,
21769           'file': noop
21770         };
21771
21772         function stringBasedInputType(ctrl) {
21773           ctrl.$formatters.push(function(value) {
21774             return ctrl.$isEmpty(value) ? value : value.toString();
21775           });
21776         }
21777
21778         function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21779           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21780           stringBasedInputType(ctrl);
21781         }
21782
21783         function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21784           var type = lowercase(element[0].type);
21785
21786           // In composition mode, users are still inputing intermediate text buffer,
21787           // hold the listener until composition is done.
21788           // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
21789           if (!$sniffer.android) {
21790             var composing = false;
21791
21792             element.on('compositionstart', function(data) {
21793               composing = true;
21794             });
21795
21796             element.on('compositionend', function() {
21797               composing = false;
21798               listener();
21799             });
21800           }
21801
21802           var listener = function(ev) {
21803             if (timeout) {
21804               $browser.defer.cancel(timeout);
21805               timeout = null;
21806             }
21807             if (composing) return;
21808             var value = element.val(),
21809                 event = ev && ev.type;
21810
21811             // By default we will trim the value
21812             // If the attribute ng-trim exists we will avoid trimming
21813             // If input type is 'password', the value is never trimmed
21814             if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
21815               value = trim(value);
21816             }
21817
21818             // If a control is suffering from bad input (due to native validators), browsers discard its
21819             // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
21820             // control's value is the same empty value twice in a row.
21821             if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
21822               ctrl.$setViewValue(value, event);
21823             }
21824           };
21825
21826           // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
21827           // input event on backspace, delete or cut
21828           if ($sniffer.hasEvent('input')) {
21829             element.on('input', listener);
21830           } else {
21831             var timeout;
21832
21833             var deferListener = function(ev, input, origValue) {
21834               if (!timeout) {
21835                 timeout = $browser.defer(function() {
21836                   timeout = null;
21837                   if (!input || input.value !== origValue) {
21838                     listener(ev);
21839                   }
21840                 });
21841               }
21842             };
21843
21844             element.on('keydown', function(event) {
21845               var key = event.keyCode;
21846
21847               // ignore
21848               //    command            modifiers                   arrows
21849               if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
21850
21851               deferListener(event, this, this.value);
21852             });
21853
21854             // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
21855             if ($sniffer.hasEvent('paste')) {
21856               element.on('paste cut', deferListener);
21857             }
21858           }
21859
21860           // if user paste into input using mouse on older browser
21861           // or form autocomplete on newer browser, we need "change" event to catch it
21862           element.on('change', listener);
21863
21864           ctrl.$render = function() {
21865             // Workaround for Firefox validation #12102.
21866             var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
21867             if (element.val() !== value) {
21868               element.val(value);
21869             }
21870           };
21871         }
21872
21873         function weekParser(isoWeek, existingDate) {
21874           if (isDate(isoWeek)) {
21875             return isoWeek;
21876           }
21877
21878           if (isString(isoWeek)) {
21879             WEEK_REGEXP.lastIndex = 0;
21880             var parts = WEEK_REGEXP.exec(isoWeek);
21881             if (parts) {
21882               var year = +parts[1],
21883                   week = +parts[2],
21884                   hours = 0,
21885                   minutes = 0,
21886                   seconds = 0,
21887                   milliseconds = 0,
21888                   firstThurs = getFirstThursdayOfYear(year),
21889                   addDays = (week - 1) * 7;
21890
21891               if (existingDate) {
21892                 hours = existingDate.getHours();
21893                 minutes = existingDate.getMinutes();
21894                 seconds = existingDate.getSeconds();
21895                 milliseconds = existingDate.getMilliseconds();
21896               }
21897
21898               return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
21899             }
21900           }
21901
21902           return NaN;
21903         }
21904
21905         function createDateParser(regexp, mapping) {
21906           return function(iso, date) {
21907             var parts, map;
21908
21909             if (isDate(iso)) {
21910               return iso;
21911             }
21912
21913             if (isString(iso)) {
21914               // When a date is JSON'ified to wraps itself inside of an extra
21915               // set of double quotes. This makes the date parsing code unable
21916               // to match the date string and parse it as a date.
21917               if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
21918                 iso = iso.substring(1, iso.length - 1);
21919               }
21920               if (ISO_DATE_REGEXP.test(iso)) {
21921                 return new Date(iso);
21922               }
21923               regexp.lastIndex = 0;
21924               parts = regexp.exec(iso);
21925
21926               if (parts) {
21927                 parts.shift();
21928                 if (date) {
21929                   map = {
21930                     yyyy: date.getFullYear(),
21931                     MM: date.getMonth() + 1,
21932                     dd: date.getDate(),
21933                     HH: date.getHours(),
21934                     mm: date.getMinutes(),
21935                     ss: date.getSeconds(),
21936                     sss: date.getMilliseconds() / 1000
21937                   };
21938                 } else {
21939                   map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
21940                 }
21941
21942                 forEach(parts, function(part, index) {
21943                   if (index < mapping.length) {
21944                     map[mapping[index]] = +part;
21945                   }
21946                 });
21947                 return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
21948               }
21949             }
21950
21951             return NaN;
21952           };
21953         }
21954
21955         function createDateInputType(type, regexp, parseDate, format) {
21956           return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
21957             badInputChecker(scope, element, attr, ctrl);
21958             baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21959             var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
21960             var previousDate;
21961
21962             ctrl.$$parserName = type;
21963             ctrl.$parsers.push(function(value) {
21964               if (ctrl.$isEmpty(value)) return null;
21965               if (regexp.test(value)) {
21966                 // Note: We cannot read ctrl.$modelValue, as there might be a different
21967                 // parser/formatter in the processing chain so that the model
21968                 // contains some different data format!
21969                 var parsedDate = parseDate(value, previousDate);
21970                 if (timezone) {
21971                   parsedDate = convertTimezoneToLocal(parsedDate, timezone);
21972                 }
21973                 return parsedDate;
21974               }
21975               return undefined;
21976             });
21977
21978             ctrl.$formatters.push(function(value) {
21979               if (value && !isDate(value)) {
21980                 throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
21981               }
21982               if (isValidDate(value)) {
21983                 previousDate = value;
21984                 if (previousDate && timezone) {
21985                   previousDate = convertTimezoneToLocal(previousDate, timezone, true);
21986                 }
21987                 return $filter('date')(value, format, timezone);
21988               } else {
21989                 previousDate = null;
21990                 return '';
21991               }
21992             });
21993
21994             if (isDefined(attr.min) || attr.ngMin) {
21995               var minVal;
21996               ctrl.$validators.min = function(value) {
21997                 return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
21998               };
21999               attr.$observe('min', function(val) {
22000                 minVal = parseObservedDateValue(val);
22001                 ctrl.$validate();
22002               });
22003             }
22004
22005             if (isDefined(attr.max) || attr.ngMax) {
22006               var maxVal;
22007               ctrl.$validators.max = function(value) {
22008                 return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
22009               };
22010               attr.$observe('max', function(val) {
22011                 maxVal = parseObservedDateValue(val);
22012                 ctrl.$validate();
22013               });
22014             }
22015
22016             function isValidDate(value) {
22017               // Invalid Date: getTime() returns NaN
22018               return value && !(value.getTime && value.getTime() !== value.getTime());
22019             }
22020
22021             function parseObservedDateValue(val) {
22022               return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
22023             }
22024           };
22025         }
22026
22027         function badInputChecker(scope, element, attr, ctrl) {
22028           var node = element[0];
22029           var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
22030           if (nativeValidation) {
22031             ctrl.$parsers.push(function(value) {
22032               var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
22033               // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
22034               // - also sets validity.badInput (should only be validity.typeMismatch).
22035               // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
22036               // - can ignore this case as we can still read out the erroneous email...
22037               return validity.badInput && !validity.typeMismatch ? undefined : value;
22038             });
22039           }
22040         }
22041
22042         function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22043           badInputChecker(scope, element, attr, ctrl);
22044           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22045
22046           ctrl.$$parserName = 'number';
22047           ctrl.$parsers.push(function(value) {
22048             if (ctrl.$isEmpty(value))      return null;
22049             if (NUMBER_REGEXP.test(value)) return parseFloat(value);
22050             return undefined;
22051           });
22052
22053           ctrl.$formatters.push(function(value) {
22054             if (!ctrl.$isEmpty(value)) {
22055               if (!isNumber(value)) {
22056                 throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
22057               }
22058               value = value.toString();
22059             }
22060             return value;
22061           });
22062
22063           if (isDefined(attr.min) || attr.ngMin) {
22064             var minVal;
22065             ctrl.$validators.min = function(value) {
22066               return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
22067             };
22068
22069             attr.$observe('min', function(val) {
22070               if (isDefined(val) && !isNumber(val)) {
22071                 val = parseFloat(val, 10);
22072               }
22073               minVal = isNumber(val) && !isNaN(val) ? val : undefined;
22074               // TODO(matsko): implement validateLater to reduce number of validations
22075               ctrl.$validate();
22076             });
22077           }
22078
22079           if (isDefined(attr.max) || attr.ngMax) {
22080             var maxVal;
22081             ctrl.$validators.max = function(value) {
22082               return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
22083             };
22084
22085             attr.$observe('max', function(val) {
22086               if (isDefined(val) && !isNumber(val)) {
22087                 val = parseFloat(val, 10);
22088               }
22089               maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
22090               // TODO(matsko): implement validateLater to reduce number of validations
22091               ctrl.$validate();
22092             });
22093           }
22094         }
22095
22096         function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22097           // Note: no badInputChecker here by purpose as `url` is only a validation
22098           // in browsers, i.e. we can always read out input.value even if it is not valid!
22099           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22100           stringBasedInputType(ctrl);
22101
22102           ctrl.$$parserName = 'url';
22103           ctrl.$validators.url = function(modelValue, viewValue) {
22104             var value = modelValue || viewValue;
22105             return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
22106           };
22107         }
22108
22109         function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22110           // Note: no badInputChecker here by purpose as `url` is only a validation
22111           // in browsers, i.e. we can always read out input.value even if it is not valid!
22112           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22113           stringBasedInputType(ctrl);
22114
22115           ctrl.$$parserName = 'email';
22116           ctrl.$validators.email = function(modelValue, viewValue) {
22117             var value = modelValue || viewValue;
22118             return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
22119           };
22120         }
22121
22122         function radioInputType(scope, element, attr, ctrl) {
22123           // make the name unique, if not defined
22124           if (isUndefined(attr.name)) {
22125             element.attr('name', nextUid());
22126           }
22127
22128           var listener = function(ev) {
22129             if (element[0].checked) {
22130               ctrl.$setViewValue(attr.value, ev && ev.type);
22131             }
22132           };
22133
22134           element.on('click', listener);
22135
22136           ctrl.$render = function() {
22137             var value = attr.value;
22138             element[0].checked = (value == ctrl.$viewValue);
22139           };
22140
22141           attr.$observe('value', ctrl.$render);
22142         }
22143
22144         function parseConstantExpr($parse, context, name, expression, fallback) {
22145           var parseFn;
22146           if (isDefined(expression)) {
22147             parseFn = $parse(expression);
22148             if (!parseFn.constant) {
22149               throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
22150                                            '`{1}`.', name, expression);
22151             }
22152             return parseFn(context);
22153           }
22154           return fallback;
22155         }
22156
22157         function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
22158           var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
22159           var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
22160
22161           var listener = function(ev) {
22162             ctrl.$setViewValue(element[0].checked, ev && ev.type);
22163           };
22164
22165           element.on('click', listener);
22166
22167           ctrl.$render = function() {
22168             element[0].checked = ctrl.$viewValue;
22169           };
22170
22171           // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
22172           // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
22173           // it to a boolean.
22174           ctrl.$isEmpty = function(value) {
22175             return value === false;
22176           };
22177
22178           ctrl.$formatters.push(function(value) {
22179             return equals(value, trueValue);
22180           });
22181
22182           ctrl.$parsers.push(function(value) {
22183             return value ? trueValue : falseValue;
22184           });
22185         }
22186
22187
22188         /**
22189          * @ngdoc directive
22190          * @name textarea
22191          * @restrict E
22192          *
22193          * @description
22194          * HTML textarea element control with angular data-binding. The data-binding and validation
22195          * properties of this element are exactly the same as those of the
22196          * {@link ng.directive:input input element}.
22197          *
22198          * @param {string} ngModel Assignable angular expression to data-bind to.
22199          * @param {string=} name Property name of the form under which the control is published.
22200          * @param {string=} required Sets `required` validation error key if the value is not entered.
22201          * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
22202          *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
22203          *    `required` when you want to data-bind to the `required` attribute.
22204          * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22205          *    minlength.
22206          * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22207          *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22208          *    length.
22209          * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22210          *    a RegExp found by evaluating the Angular expression given in the attribute value.
22211          *    If the expression evaluates to a RegExp object, then this is used directly.
22212          *    If the expression evaluates to a string, then it will be converted to a RegExp
22213          *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
22214          *    `new RegExp('^abc$')`.<br />
22215          *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
22216          *    start at the index of the last search's match, thus not taking the whole input value into
22217          *    account.
22218          * @param {string=} ngChange Angular expression to be executed when input changes due to user
22219          *    interaction with the input element.
22220          * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22221          */
22222
22223
22224         /**
22225          * @ngdoc directive
22226          * @name input
22227          * @restrict E
22228          *
22229          * @description
22230          * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
22231          * input state control, and validation.
22232          * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
22233          *
22234          * <div class="alert alert-warning">
22235          * **Note:** Not every feature offered is available for all input types.
22236          * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
22237          * </div>
22238          *
22239          * @param {string} ngModel Assignable angular expression to data-bind to.
22240          * @param {string=} name Property name of the form under which the control is published.
22241          * @param {string=} required Sets `required` validation error key if the value is not entered.
22242          * @param {boolean=} ngRequired Sets `required` attribute if set to true
22243          * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22244          *    minlength.
22245          * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22246          *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22247          *    length.
22248          * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22249          *    a RegExp found by evaluating the Angular expression given in the attribute value.
22250          *    If the expression evaluates to a RegExp object, then this is used directly.
22251          *    If the expression evaluates to a string, then it will be converted to a RegExp
22252          *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
22253          *    `new RegExp('^abc$')`.<br />
22254          *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
22255          *    start at the index of the last search's match, thus not taking the whole input value into
22256          *    account.
22257          * @param {string=} ngChange Angular expression to be executed when input changes due to user
22258          *    interaction with the input element.
22259          * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22260          *    This parameter is ignored for input[type=password] controls, which will never trim the
22261          *    input.
22262          *
22263          * @example
22264             <example name="input-directive" module="inputExample">
22265               <file name="index.html">
22266                <script>
22267                   angular.module('inputExample', [])
22268                     .controller('ExampleController', ['$scope', function($scope) {
22269                       $scope.user = {name: 'guest', last: 'visitor'};
22270                     }]);
22271                </script>
22272                <div ng-controller="ExampleController">
22273                  <form name="myForm">
22274                    <label>
22275                       User name:
22276                       <input type="text" name="userName" ng-model="user.name" required>
22277                    </label>
22278                    <div role="alert">
22279                      <span class="error" ng-show="myForm.userName.$error.required">
22280                       Required!</span>
22281                    </div>
22282                    <label>
22283                       Last name:
22284                       <input type="text" name="lastName" ng-model="user.last"
22285                       ng-minlength="3" ng-maxlength="10">
22286                    </label>
22287                    <div role="alert">
22288                      <span class="error" ng-show="myForm.lastName.$error.minlength">
22289                        Too short!</span>
22290                      <span class="error" ng-show="myForm.lastName.$error.maxlength">
22291                        Too long!</span>
22292                    </div>
22293                  </form>
22294                  <hr>
22295                  <tt>user = {{user}}</tt><br/>
22296                  <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
22297                  <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
22298                  <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
22299                  <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
22300                  <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
22301                  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
22302                  <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
22303                  <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
22304                </div>
22305               </file>
22306               <file name="protractor.js" type="protractor">
22307                 var user = element(by.exactBinding('user'));
22308                 var userNameValid = element(by.binding('myForm.userName.$valid'));
22309                 var lastNameValid = element(by.binding('myForm.lastName.$valid'));
22310                 var lastNameError = element(by.binding('myForm.lastName.$error'));
22311                 var formValid = element(by.binding('myForm.$valid'));
22312                 var userNameInput = element(by.model('user.name'));
22313                 var userLastInput = element(by.model('user.last'));
22314
22315                 it('should initialize to model', function() {
22316                   expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
22317                   expect(userNameValid.getText()).toContain('true');
22318                   expect(formValid.getText()).toContain('true');
22319                 });
22320
22321                 it('should be invalid if empty when required', function() {
22322                   userNameInput.clear();
22323                   userNameInput.sendKeys('');
22324
22325                   expect(user.getText()).toContain('{"last":"visitor"}');
22326                   expect(userNameValid.getText()).toContain('false');
22327                   expect(formValid.getText()).toContain('false');
22328                 });
22329
22330                 it('should be valid if empty when min length is set', function() {
22331                   userLastInput.clear();
22332                   userLastInput.sendKeys('');
22333
22334                   expect(user.getText()).toContain('{"name":"guest","last":""}');
22335                   expect(lastNameValid.getText()).toContain('true');
22336                   expect(formValid.getText()).toContain('true');
22337                 });
22338
22339                 it('should be invalid if less than required min length', function() {
22340                   userLastInput.clear();
22341                   userLastInput.sendKeys('xx');
22342
22343                   expect(user.getText()).toContain('{"name":"guest"}');
22344                   expect(lastNameValid.getText()).toContain('false');
22345                   expect(lastNameError.getText()).toContain('minlength');
22346                   expect(formValid.getText()).toContain('false');
22347                 });
22348
22349                 it('should be invalid if longer than max length', function() {
22350                   userLastInput.clear();
22351                   userLastInput.sendKeys('some ridiculously long name');
22352
22353                   expect(user.getText()).toContain('{"name":"guest"}');
22354                   expect(lastNameValid.getText()).toContain('false');
22355                   expect(lastNameError.getText()).toContain('maxlength');
22356                   expect(formValid.getText()).toContain('false');
22357                 });
22358               </file>
22359             </example>
22360          */
22361         var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
22362             function($browser, $sniffer, $filter, $parse) {
22363           return {
22364             restrict: 'E',
22365             require: ['?ngModel'],
22366             link: {
22367               pre: function(scope, element, attr, ctrls) {
22368                 if (ctrls[0]) {
22369                   (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
22370                                                                       $browser, $filter, $parse);
22371                 }
22372               }
22373             }
22374           };
22375         }];
22376
22377
22378
22379         var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
22380         /**
22381          * @ngdoc directive
22382          * @name ngValue
22383          *
22384          * @description
22385          * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
22386          * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
22387          * the bound value.
22388          *
22389          * `ngValue` is useful when dynamically generating lists of radio buttons using
22390          * {@link ngRepeat `ngRepeat`}, as shown below.
22391          *
22392          * Likewise, `ngValue` can be used to generate `<option>` elements for
22393          * the {@link select `select`} element. In that case however, only strings are supported
22394          * for the `value `attribute, so the resulting `ngModel` will always be a string.
22395          * Support for `select` models with non-string values is available via `ngOptions`.
22396          *
22397          * @element input
22398          * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
22399          *   of the `input` element
22400          *
22401          * @example
22402             <example name="ngValue-directive" module="valueExample">
22403               <file name="index.html">
22404                <script>
22405                   angular.module('valueExample', [])
22406                     .controller('ExampleController', ['$scope', function($scope) {
22407                       $scope.names = ['pizza', 'unicorns', 'robots'];
22408                       $scope.my = { favorite: 'unicorns' };
22409                     }]);
22410                </script>
22411                 <form ng-controller="ExampleController">
22412                   <h2>Which is your favorite?</h2>
22413                     <label ng-repeat="name in names" for="{{name}}">
22414                       {{name}}
22415                       <input type="radio"
22416                              ng-model="my.favorite"
22417                              ng-value="name"
22418                              id="{{name}}"
22419                              name="favorite">
22420                     </label>
22421                   <div>You chose {{my.favorite}}</div>
22422                 </form>
22423               </file>
22424               <file name="protractor.js" type="protractor">
22425                 var favorite = element(by.binding('my.favorite'));
22426
22427                 it('should initialize to model', function() {
22428                   expect(favorite.getText()).toContain('unicorns');
22429                 });
22430                 it('should bind the values to the inputs', function() {
22431                   element.all(by.model('my.favorite')).get(0).click();
22432                   expect(favorite.getText()).toContain('pizza');
22433                 });
22434               </file>
22435             </example>
22436          */
22437         var ngValueDirective = function() {
22438           return {
22439             restrict: 'A',
22440             priority: 100,
22441             compile: function(tpl, tplAttr) {
22442               if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
22443                 return function ngValueConstantLink(scope, elm, attr) {
22444                   attr.$set('value', scope.$eval(attr.ngValue));
22445                 };
22446               } else {
22447                 return function ngValueLink(scope, elm, attr) {
22448                   scope.$watch(attr.ngValue, function valueWatchAction(value) {
22449                     attr.$set('value', value);
22450                   });
22451                 };
22452               }
22453             }
22454           };
22455         };
22456
22457         /**
22458          * @ngdoc directive
22459          * @name ngBind
22460          * @restrict AC
22461          *
22462          * @description
22463          * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
22464          * with the value of a given expression, and to update the text content when the value of that
22465          * expression changes.
22466          *
22467          * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
22468          * `{{ expression }}` which is similar but less verbose.
22469          *
22470          * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
22471          * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
22472          * element attribute, it makes the bindings invisible to the user while the page is loading.
22473          *
22474          * An alternative solution to this problem would be using the
22475          * {@link ng.directive:ngCloak ngCloak} directive.
22476          *
22477          *
22478          * @element ANY
22479          * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
22480          *
22481          * @example
22482          * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
22483            <example module="bindExample">
22484              <file name="index.html">
22485                <script>
22486                  angular.module('bindExample', [])
22487                    .controller('ExampleController', ['$scope', function($scope) {
22488                      $scope.name = 'Whirled';
22489                    }]);
22490                </script>
22491                <div ng-controller="ExampleController">
22492                  <label>Enter name: <input type="text" ng-model="name"></label><br>
22493                  Hello <span ng-bind="name"></span>!
22494                </div>
22495              </file>
22496              <file name="protractor.js" type="protractor">
22497                it('should check ng-bind', function() {
22498                  var nameInput = element(by.model('name'));
22499
22500                  expect(element(by.binding('name')).getText()).toBe('Whirled');
22501                  nameInput.clear();
22502                  nameInput.sendKeys('world');
22503                  expect(element(by.binding('name')).getText()).toBe('world');
22504                });
22505              </file>
22506            </example>
22507          */
22508         var ngBindDirective = ['$compile', function($compile) {
22509           return {
22510             restrict: 'AC',
22511             compile: function ngBindCompile(templateElement) {
22512               $compile.$$addBindingClass(templateElement);
22513               return function ngBindLink(scope, element, attr) {
22514                 $compile.$$addBindingInfo(element, attr.ngBind);
22515                 element = element[0];
22516                 scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
22517                   element.textContent = isUndefined(value) ? '' : value;
22518                 });
22519               };
22520             }
22521           };
22522         }];
22523
22524
22525         /**
22526          * @ngdoc directive
22527          * @name ngBindTemplate
22528          *
22529          * @description
22530          * The `ngBindTemplate` directive specifies that the element
22531          * text content should be replaced with the interpolation of the template
22532          * in the `ngBindTemplate` attribute.
22533          * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
22534          * expressions. This directive is needed since some HTML elements
22535          * (such as TITLE and OPTION) cannot contain SPAN elements.
22536          *
22537          * @element ANY
22538          * @param {string} ngBindTemplate template of form
22539          *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
22540          *
22541          * @example
22542          * Try it here: enter text in text box and watch the greeting change.
22543            <example module="bindExample">
22544              <file name="index.html">
22545                <script>
22546                  angular.module('bindExample', [])
22547                    .controller('ExampleController', ['$scope', function($scope) {
22548                      $scope.salutation = 'Hello';
22549                      $scope.name = 'World';
22550                    }]);
22551                </script>
22552                <div ng-controller="ExampleController">
22553                 <label>Salutation: <input type="text" ng-model="salutation"></label><br>
22554                 <label>Name: <input type="text" ng-model="name"></label><br>
22555                 <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
22556                </div>
22557              </file>
22558              <file name="protractor.js" type="protractor">
22559                it('should check ng-bind', function() {
22560                  var salutationElem = element(by.binding('salutation'));
22561                  var salutationInput = element(by.model('salutation'));
22562                  var nameInput = element(by.model('name'));
22563
22564                  expect(salutationElem.getText()).toBe('Hello World!');
22565
22566                  salutationInput.clear();
22567                  salutationInput.sendKeys('Greetings');
22568                  nameInput.clear();
22569                  nameInput.sendKeys('user');
22570
22571                  expect(salutationElem.getText()).toBe('Greetings user!');
22572                });
22573              </file>
22574            </example>
22575          */
22576         var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
22577           return {
22578             compile: function ngBindTemplateCompile(templateElement) {
22579               $compile.$$addBindingClass(templateElement);
22580               return function ngBindTemplateLink(scope, element, attr) {
22581                 var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
22582                 $compile.$$addBindingInfo(element, interpolateFn.expressions);
22583                 element = element[0];
22584                 attr.$observe('ngBindTemplate', function(value) {
22585                   element.textContent = isUndefined(value) ? '' : value;
22586                 });
22587               };
22588             }
22589           };
22590         }];
22591
22592
22593         /**
22594          * @ngdoc directive
22595          * @name ngBindHtml
22596          *
22597          * @description
22598          * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
22599          * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
22600          * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
22601          * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
22602          * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
22603          *
22604          * You may also bypass sanitization for values you know are safe. To do so, bind to
22605          * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
22606          * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
22607          *
22608          * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
22609          * will have an exception (instead of an exploit.)
22610          *
22611          * @element ANY
22612          * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
22613          *
22614          * @example
22615
22616            <example module="bindHtmlExample" deps="angular-sanitize.js">
22617              <file name="index.html">
22618                <div ng-controller="ExampleController">
22619                 <p ng-bind-html="myHTML"></p>
22620                </div>
22621              </file>
22622
22623              <file name="script.js">
22624                angular.module('bindHtmlExample', ['ngSanitize'])
22625                  .controller('ExampleController', ['$scope', function($scope) {
22626                    $scope.myHTML =
22627                       'I am an <code>HTML</code>string with ' +
22628                       '<a href="#">links!</a> and other <em>stuff</em>';
22629                  }]);
22630              </file>
22631
22632              <file name="protractor.js" type="protractor">
22633                it('should check ng-bind-html', function() {
22634                  expect(element(by.binding('myHTML')).getText()).toBe(
22635                      'I am an HTMLstring with links! and other stuff');
22636                });
22637              </file>
22638            </example>
22639          */
22640         var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
22641           return {
22642             restrict: 'A',
22643             compile: function ngBindHtmlCompile(tElement, tAttrs) {
22644               var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
22645               var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
22646                 return (value || '').toString();
22647               });
22648               $compile.$$addBindingClass(tElement);
22649
22650               return function ngBindHtmlLink(scope, element, attr) {
22651                 $compile.$$addBindingInfo(element, attr.ngBindHtml);
22652
22653                 scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
22654                   // we re-evaluate the expr because we want a TrustedValueHolderType
22655                   // for $sce, not a string
22656                   element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
22657                 });
22658               };
22659             }
22660           };
22661         }];
22662
22663         /**
22664          * @ngdoc directive
22665          * @name ngChange
22666          *
22667          * @description
22668          * Evaluate the given expression when the user changes the input.
22669          * The expression is evaluated immediately, unlike the JavaScript onchange event
22670          * which only triggers at the end of a change (usually, when the user leaves the
22671          * form element or presses the return key).
22672          *
22673          * The `ngChange` expression is only evaluated when a change in the input value causes
22674          * a new value to be committed to the model.
22675          *
22676          * It will not be evaluated:
22677          * * if the value returned from the `$parsers` transformation pipeline has not changed
22678          * * if the input has continued to be invalid since the model will stay `null`
22679          * * if the model is changed programmatically and not by a change to the input value
22680          *
22681          *
22682          * Note, this directive requires `ngModel` to be present.
22683          *
22684          * @element input
22685          * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
22686          * in input value.
22687          *
22688          * @example
22689          * <example name="ngChange-directive" module="changeExample">
22690          *   <file name="index.html">
22691          *     <script>
22692          *       angular.module('changeExample', [])
22693          *         .controller('ExampleController', ['$scope', function($scope) {
22694          *           $scope.counter = 0;
22695          *           $scope.change = function() {
22696          *             $scope.counter++;
22697          *           };
22698          *         }]);
22699          *     </script>
22700          *     <div ng-controller="ExampleController">
22701          *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
22702          *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
22703          *       <label for="ng-change-example2">Confirmed</label><br />
22704          *       <tt>debug = {{confirmed}}</tt><br/>
22705          *       <tt>counter = {{counter}}</tt><br/>
22706          *     </div>
22707          *   </file>
22708          *   <file name="protractor.js" type="protractor">
22709          *     var counter = element(by.binding('counter'));
22710          *     var debug = element(by.binding('confirmed'));
22711          *
22712          *     it('should evaluate the expression if changing from view', function() {
22713          *       expect(counter.getText()).toContain('0');
22714          *
22715          *       element(by.id('ng-change-example1')).click();
22716          *
22717          *       expect(counter.getText()).toContain('1');
22718          *       expect(debug.getText()).toContain('true');
22719          *     });
22720          *
22721          *     it('should not evaluate the expression if changing from model', function() {
22722          *       element(by.id('ng-change-example2')).click();
22723
22724          *       expect(counter.getText()).toContain('0');
22725          *       expect(debug.getText()).toContain('true');
22726          *     });
22727          *   </file>
22728          * </example>
22729          */
22730         var ngChangeDirective = valueFn({
22731           restrict: 'A',
22732           require: 'ngModel',
22733           link: function(scope, element, attr, ctrl) {
22734             ctrl.$viewChangeListeners.push(function() {
22735               scope.$eval(attr.ngChange);
22736             });
22737           }
22738         });
22739
22740         function classDirective(name, selector) {
22741           name = 'ngClass' + name;
22742           return ['$animate', function($animate) {
22743             return {
22744               restrict: 'AC',
22745               link: function(scope, element, attr) {
22746                 var oldVal;
22747
22748                 scope.$watch(attr[name], ngClassWatchAction, true);
22749
22750                 attr.$observe('class', function(value) {
22751                   ngClassWatchAction(scope.$eval(attr[name]));
22752                 });
22753
22754
22755                 if (name !== 'ngClass') {
22756                   scope.$watch('$index', function($index, old$index) {
22757                     // jshint bitwise: false
22758                     var mod = $index & 1;
22759                     if (mod !== (old$index & 1)) {
22760                       var classes = arrayClasses(scope.$eval(attr[name]));
22761                       mod === selector ?
22762                         addClasses(classes) :
22763                         removeClasses(classes);
22764                     }
22765                   });
22766                 }
22767
22768                 function addClasses(classes) {
22769                   var newClasses = digestClassCounts(classes, 1);
22770                   attr.$addClass(newClasses);
22771                 }
22772
22773                 function removeClasses(classes) {
22774                   var newClasses = digestClassCounts(classes, -1);
22775                   attr.$removeClass(newClasses);
22776                 }
22777
22778                 function digestClassCounts(classes, count) {
22779                   // Use createMap() to prevent class assumptions involving property
22780                   // names in Object.prototype
22781                   var classCounts = element.data('$classCounts') || createMap();
22782                   var classesToUpdate = [];
22783                   forEach(classes, function(className) {
22784                     if (count > 0 || classCounts[className]) {
22785                       classCounts[className] = (classCounts[className] || 0) + count;
22786                       if (classCounts[className] === +(count > 0)) {
22787                         classesToUpdate.push(className);
22788                       }
22789                     }
22790                   });
22791                   element.data('$classCounts', classCounts);
22792                   return classesToUpdate.join(' ');
22793                 }
22794
22795                 function updateClasses(oldClasses, newClasses) {
22796                   var toAdd = arrayDifference(newClasses, oldClasses);
22797                   var toRemove = arrayDifference(oldClasses, newClasses);
22798                   toAdd = digestClassCounts(toAdd, 1);
22799                   toRemove = digestClassCounts(toRemove, -1);
22800                   if (toAdd && toAdd.length) {
22801                     $animate.addClass(element, toAdd);
22802                   }
22803                   if (toRemove && toRemove.length) {
22804                     $animate.removeClass(element, toRemove);
22805                   }
22806                 }
22807
22808                 function ngClassWatchAction(newVal) {
22809                   if (selector === true || scope.$index % 2 === selector) {
22810                     var newClasses = arrayClasses(newVal || []);
22811                     if (!oldVal) {
22812                       addClasses(newClasses);
22813                     } else if (!equals(newVal,oldVal)) {
22814                       var oldClasses = arrayClasses(oldVal);
22815                       updateClasses(oldClasses, newClasses);
22816                     }
22817                   }
22818                   oldVal = shallowCopy(newVal);
22819                 }
22820               }
22821             };
22822
22823             function arrayDifference(tokens1, tokens2) {
22824               var values = [];
22825
22826               outer:
22827               for (var i = 0; i < tokens1.length; i++) {
22828                 var token = tokens1[i];
22829                 for (var j = 0; j < tokens2.length; j++) {
22830                   if (token == tokens2[j]) continue outer;
22831                 }
22832                 values.push(token);
22833               }
22834               return values;
22835             }
22836
22837             function arrayClasses(classVal) {
22838               var classes = [];
22839               if (isArray(classVal)) {
22840                 forEach(classVal, function(v) {
22841                   classes = classes.concat(arrayClasses(v));
22842                 });
22843                 return classes;
22844               } else if (isString(classVal)) {
22845                 return classVal.split(' ');
22846               } else if (isObject(classVal)) {
22847                 forEach(classVal, function(v, k) {
22848                   if (v) {
22849                     classes = classes.concat(k.split(' '));
22850                   }
22851                 });
22852                 return classes;
22853               }
22854               return classVal;
22855             }
22856           }];
22857         }
22858
22859         /**
22860          * @ngdoc directive
22861          * @name ngClass
22862          * @restrict AC
22863          *
22864          * @description
22865          * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
22866          * an expression that represents all classes to be added.
22867          *
22868          * The directive operates in three different ways, depending on which of three types the expression
22869          * evaluates to:
22870          *
22871          * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
22872          * names.
22873          *
22874          * 2. If the expression evaluates to an object, then for each key-value pair of the
22875          * object with a truthy value the corresponding key is used as a class name.
22876          *
22877          * 3. If the expression evaluates to an array, each element of the array should either be a string as in
22878          * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
22879          * to give you more control over what CSS classes appear. See the code below for an example of this.
22880          *
22881          *
22882          * The directive won't add duplicate classes if a particular class was already set.
22883          *
22884          * When the expression changes, the previously added classes are removed and only then are the
22885          * new classes added.
22886          *
22887          * @animations
22888          * **add** - happens just before the class is applied to the elements
22889          *
22890          * **remove** - happens just before the class is removed from the element
22891          *
22892          * @element ANY
22893          * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
22894          *   of the evaluation can be a string representing space delimited class
22895          *   names, an array, or a map of class names to boolean values. In the case of a map, the
22896          *   names of the properties whose values are truthy will be added as css classes to the
22897          *   element.
22898          *
22899          * @example Example that demonstrates basic bindings via ngClass directive.
22900            <example>
22901              <file name="index.html">
22902                <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
22903                <label>
22904                   <input type="checkbox" ng-model="deleted">
22905                   deleted (apply "strike" class)
22906                </label><br>
22907                <label>
22908                   <input type="checkbox" ng-model="important">
22909                   important (apply "bold" class)
22910                </label><br>
22911                <label>
22912                   <input type="checkbox" ng-model="error">
22913                   error (apply "has-error" class)
22914                </label>
22915                <hr>
22916                <p ng-class="style">Using String Syntax</p>
22917                <input type="text" ng-model="style"
22918                       placeholder="Type: bold strike red" aria-label="Type: bold strike red">
22919                <hr>
22920                <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
22921                <input ng-model="style1"
22922                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
22923                <input ng-model="style2"
22924                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
22925                <input ng-model="style3"
22926                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
22927                <hr>
22928                <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
22929                <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
22930                <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
22931              </file>
22932              <file name="style.css">
22933                .strike {
22934                    text-decoration: line-through;
22935                }
22936                .bold {
22937                    font-weight: bold;
22938                }
22939                .red {
22940                    color: red;
22941                }
22942                .has-error {
22943                    color: red;
22944                    background-color: yellow;
22945                }
22946                .orange {
22947                    color: orange;
22948                }
22949              </file>
22950              <file name="protractor.js" type="protractor">
22951                var ps = element.all(by.css('p'));
22952
22953                it('should let you toggle the class', function() {
22954
22955                  expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
22956                  expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
22957
22958                  element(by.model('important')).click();
22959                  expect(ps.first().getAttribute('class')).toMatch(/bold/);
22960
22961                  element(by.model('error')).click();
22962                  expect(ps.first().getAttribute('class')).toMatch(/has-error/);
22963                });
22964
22965                it('should let you toggle string example', function() {
22966                  expect(ps.get(1).getAttribute('class')).toBe('');
22967                  element(by.model('style')).clear();
22968                  element(by.model('style')).sendKeys('red');
22969                  expect(ps.get(1).getAttribute('class')).toBe('red');
22970                });
22971
22972                it('array example should have 3 classes', function() {
22973                  expect(ps.get(2).getAttribute('class')).toBe('');
22974                  element(by.model('style1')).sendKeys('bold');
22975                  element(by.model('style2')).sendKeys('strike');
22976                  element(by.model('style3')).sendKeys('red');
22977                  expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
22978                });
22979
22980                it('array with map example should have 2 classes', function() {
22981                  expect(ps.last().getAttribute('class')).toBe('');
22982                  element(by.model('style4')).sendKeys('bold');
22983                  element(by.model('warning')).click();
22984                  expect(ps.last().getAttribute('class')).toBe('bold orange');
22985                });
22986              </file>
22987            </example>
22988
22989            ## Animations
22990
22991            The example below demonstrates how to perform animations using ngClass.
22992
22993            <example module="ngAnimate" deps="angular-animate.js" animations="true">
22994              <file name="index.html">
22995               <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
22996               <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
22997               <br>
22998               <span class="base-class" ng-class="myVar">Sample Text</span>
22999              </file>
23000              <file name="style.css">
23001                .base-class {
23002                  transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23003                }
23004
23005                .base-class.my-class {
23006                  color: red;
23007                  font-size:3em;
23008                }
23009              </file>
23010              <file name="protractor.js" type="protractor">
23011                it('should check ng-class', function() {
23012                  expect(element(by.css('.base-class')).getAttribute('class')).not.
23013                    toMatch(/my-class/);
23014
23015                  element(by.id('setbtn')).click();
23016
23017                  expect(element(by.css('.base-class')).getAttribute('class')).
23018                    toMatch(/my-class/);
23019
23020                  element(by.id('clearbtn')).click();
23021
23022                  expect(element(by.css('.base-class')).getAttribute('class')).not.
23023                    toMatch(/my-class/);
23024                });
23025              </file>
23026            </example>
23027
23028
23029            ## ngClass and pre-existing CSS3 Transitions/Animations
23030            The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
23031            Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
23032            any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
23033            to view the step by step details of {@link $animate#addClass $animate.addClass} and
23034            {@link $animate#removeClass $animate.removeClass}.
23035          */
23036         var ngClassDirective = classDirective('', true);
23037
23038         /**
23039          * @ngdoc directive
23040          * @name ngClassOdd
23041          * @restrict AC
23042          *
23043          * @description
23044          * The `ngClassOdd` and `ngClassEven` directives work exactly as
23045          * {@link ng.directive:ngClass ngClass}, except they work in
23046          * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23047          *
23048          * This directive can be applied only within the scope of an
23049          * {@link ng.directive:ngRepeat ngRepeat}.
23050          *
23051          * @element ANY
23052          * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
23053          *   of the evaluation can be a string representing space delimited class names or an array.
23054          *
23055          * @example
23056            <example>
23057              <file name="index.html">
23058                 <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23059                   <li ng-repeat="name in names">
23060                    <span ng-class-odd="'odd'" ng-class-even="'even'">
23061                      {{name}}
23062                    </span>
23063                   </li>
23064                 </ol>
23065              </file>
23066              <file name="style.css">
23067                .odd {
23068                  color: red;
23069                }
23070                .even {
23071                  color: blue;
23072                }
23073              </file>
23074              <file name="protractor.js" type="protractor">
23075                it('should check ng-class-odd and ng-class-even', function() {
23076                  expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23077                    toMatch(/odd/);
23078                  expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23079                    toMatch(/even/);
23080                });
23081              </file>
23082            </example>
23083          */
23084         var ngClassOddDirective = classDirective('Odd', 0);
23085
23086         /**
23087          * @ngdoc directive
23088          * @name ngClassEven
23089          * @restrict AC
23090          *
23091          * @description
23092          * The `ngClassOdd` and `ngClassEven` directives work exactly as
23093          * {@link ng.directive:ngClass ngClass}, except they work in
23094          * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23095          *
23096          * This directive can be applied only within the scope of an
23097          * {@link ng.directive:ngRepeat ngRepeat}.
23098          *
23099          * @element ANY
23100          * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
23101          *   result of the evaluation can be a string representing space delimited class names or an array.
23102          *
23103          * @example
23104            <example>
23105              <file name="index.html">
23106                 <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23107                   <li ng-repeat="name in names">
23108                    <span ng-class-odd="'odd'" ng-class-even="'even'">
23109                      {{name}} &nbsp; &nbsp; &nbsp;
23110                    </span>
23111                   </li>
23112                 </ol>
23113              </file>
23114              <file name="style.css">
23115                .odd {
23116                  color: red;
23117                }
23118                .even {
23119                  color: blue;
23120                }
23121              </file>
23122              <file name="protractor.js" type="protractor">
23123                it('should check ng-class-odd and ng-class-even', function() {
23124                  expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23125                    toMatch(/odd/);
23126                  expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23127                    toMatch(/even/);
23128                });
23129              </file>
23130            </example>
23131          */
23132         var ngClassEvenDirective = classDirective('Even', 1);
23133
23134         /**
23135          * @ngdoc directive
23136          * @name ngCloak
23137          * @restrict AC
23138          *
23139          * @description
23140          * The `ngCloak` directive is used to prevent the Angular html template from being briefly
23141          * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
23142          * directive to avoid the undesirable flicker effect caused by the html template display.
23143          *
23144          * The directive can be applied to the `<body>` element, but the preferred usage is to apply
23145          * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
23146          * of the browser view.
23147          *
23148          * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
23149          * `angular.min.js`.
23150          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
23151          *
23152          * ```css
23153          * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
23154          *   display: none !important;
23155          * }
23156          * ```
23157          *
23158          * When this css rule is loaded by the browser, all html elements (including their children) that
23159          * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
23160          * during the compilation of the template it deletes the `ngCloak` element attribute, making
23161          * the compiled element visible.
23162          *
23163          * For the best result, the `angular.js` script must be loaded in the head section of the html
23164          * document; alternatively, the css rule above must be included in the external stylesheet of the
23165          * application.
23166          *
23167          * @element ANY
23168          *
23169          * @example
23170            <example>
23171              <file name="index.html">
23172                 <div id="template1" ng-cloak>{{ 'hello' }}</div>
23173                 <div id="template2" class="ng-cloak">{{ 'world' }}</div>
23174              </file>
23175              <file name="protractor.js" type="protractor">
23176                it('should remove the template directive and css class', function() {
23177                  expect($('#template1').getAttribute('ng-cloak')).
23178                    toBeNull();
23179                  expect($('#template2').getAttribute('ng-cloak')).
23180                    toBeNull();
23181                });
23182              </file>
23183            </example>
23184          *
23185          */
23186         var ngCloakDirective = ngDirective({
23187           compile: function(element, attr) {
23188             attr.$set('ngCloak', undefined);
23189             element.removeClass('ng-cloak');
23190           }
23191         });
23192
23193         /**
23194          * @ngdoc directive
23195          * @name ngController
23196          *
23197          * @description
23198          * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
23199          * supports the principles behind the Model-View-Controller design pattern.
23200          *
23201          * MVC components in angular:
23202          *
23203          * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
23204          *   are accessed through bindings.
23205          * * View — The template (HTML with data bindings) that is rendered into the View.
23206          * * Controller — The `ngController` directive specifies a Controller class; the class contains business
23207          *   logic behind the application to decorate the scope with functions and values
23208          *
23209          * Note that you can also attach controllers to the DOM by declaring it in a route definition
23210          * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
23211          * again using `ng-controller` in the template itself.  This will cause the controller to be attached
23212          * and executed twice.
23213          *
23214          * @element ANY
23215          * @scope
23216          * @priority 500
23217          * @param {expression} ngController Name of a constructor function registered with the current
23218          * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
23219          * that on the current scope evaluates to a constructor function.
23220          *
23221          * The controller instance can be published into a scope property by specifying
23222          * `ng-controller="as propertyName"`.
23223          *
23224          * If the current `$controllerProvider` is configured to use globals (via
23225          * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
23226          * also be the name of a globally accessible constructor function (not recommended).
23227          *
23228          * @example
23229          * Here is a simple form for editing user contact information. Adding, removing, clearing, and
23230          * greeting are methods declared on the controller (see source tab). These methods can
23231          * easily be called from the angular markup. Any changes to the data are automatically reflected
23232          * in the View without the need for a manual update.
23233          *
23234          * Two different declaration styles are included below:
23235          *
23236          * * one binds methods and properties directly onto the controller using `this`:
23237          * `ng-controller="SettingsController1 as settings"`
23238          * * one injects `$scope` into the controller:
23239          * `ng-controller="SettingsController2"`
23240          *
23241          * The second option is more common in the Angular community, and is generally used in boilerplates
23242          * and in this guide. However, there are advantages to binding properties directly to the controller
23243          * and avoiding scope.
23244          *
23245          * * Using `controller as` makes it obvious which controller you are accessing in the template when
23246          * multiple controllers apply to an element.
23247          * * If you are writing your controllers as classes you have easier access to the properties and
23248          * methods, which will appear on the scope, from inside the controller code.
23249          * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
23250          * inheritance masking primitives.
23251          *
23252          * This example demonstrates the `controller as` syntax.
23253          *
23254          * <example name="ngControllerAs" module="controllerAsExample">
23255          *   <file name="index.html">
23256          *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
23257          *      <label>Name: <input type="text" ng-model="settings.name"/></label>
23258          *      <button ng-click="settings.greet()">greet</button><br/>
23259          *      Contact:
23260          *      <ul>
23261          *        <li ng-repeat="contact in settings.contacts">
23262          *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
23263          *             <option>phone</option>
23264          *             <option>email</option>
23265          *          </select>
23266          *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
23267          *          <button ng-click="settings.clearContact(contact)">clear</button>
23268          *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
23269          *        </li>
23270          *        <li><button ng-click="settings.addContact()">add</button></li>
23271          *     </ul>
23272          *    </div>
23273          *   </file>
23274          *   <file name="app.js">
23275          *    angular.module('controllerAsExample', [])
23276          *      .controller('SettingsController1', SettingsController1);
23277          *
23278          *    function SettingsController1() {
23279          *      this.name = "John Smith";
23280          *      this.contacts = [
23281          *        {type: 'phone', value: '408 555 1212'},
23282          *        {type: 'email', value: 'john.smith@example.org'} ];
23283          *    }
23284          *
23285          *    SettingsController1.prototype.greet = function() {
23286          *      alert(this.name);
23287          *    };
23288          *
23289          *    SettingsController1.prototype.addContact = function() {
23290          *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
23291          *    };
23292          *
23293          *    SettingsController1.prototype.removeContact = function(contactToRemove) {
23294          *     var index = this.contacts.indexOf(contactToRemove);
23295          *      this.contacts.splice(index, 1);
23296          *    };
23297          *
23298          *    SettingsController1.prototype.clearContact = function(contact) {
23299          *      contact.type = 'phone';
23300          *      contact.value = '';
23301          *    };
23302          *   </file>
23303          *   <file name="protractor.js" type="protractor">
23304          *     it('should check controller as', function() {
23305          *       var container = element(by.id('ctrl-as-exmpl'));
23306          *         expect(container.element(by.model('settings.name'))
23307          *           .getAttribute('value')).toBe('John Smith');
23308          *
23309          *       var firstRepeat =
23310          *           container.element(by.repeater('contact in settings.contacts').row(0));
23311          *       var secondRepeat =
23312          *           container.element(by.repeater('contact in settings.contacts').row(1));
23313          *
23314          *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23315          *           .toBe('408 555 1212');
23316          *
23317          *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23318          *           .toBe('john.smith@example.org');
23319          *
23320          *       firstRepeat.element(by.buttonText('clear')).click();
23321          *
23322          *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23323          *           .toBe('');
23324          *
23325          *       container.element(by.buttonText('add')).click();
23326          *
23327          *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
23328          *           .element(by.model('contact.value'))
23329          *           .getAttribute('value'))
23330          *           .toBe('yourname@example.org');
23331          *     });
23332          *   </file>
23333          * </example>
23334          *
23335          * This example demonstrates the "attach to `$scope`" style of controller.
23336          *
23337          * <example name="ngController" module="controllerExample">
23338          *  <file name="index.html">
23339          *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
23340          *     <label>Name: <input type="text" ng-model="name"/></label>
23341          *     <button ng-click="greet()">greet</button><br/>
23342          *     Contact:
23343          *     <ul>
23344          *       <li ng-repeat="contact in contacts">
23345          *         <select ng-model="contact.type" id="select_{{$index}}">
23346          *            <option>phone</option>
23347          *            <option>email</option>
23348          *         </select>
23349          *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
23350          *         <button ng-click="clearContact(contact)">clear</button>
23351          *         <button ng-click="removeContact(contact)">X</button>
23352          *       </li>
23353          *       <li>[ <button ng-click="addContact()">add</button> ]</li>
23354          *    </ul>
23355          *   </div>
23356          *  </file>
23357          *  <file name="app.js">
23358          *   angular.module('controllerExample', [])
23359          *     .controller('SettingsController2', ['$scope', SettingsController2]);
23360          *
23361          *   function SettingsController2($scope) {
23362          *     $scope.name = "John Smith";
23363          *     $scope.contacts = [
23364          *       {type:'phone', value:'408 555 1212'},
23365          *       {type:'email', value:'john.smith@example.org'} ];
23366          *
23367          *     $scope.greet = function() {
23368          *       alert($scope.name);
23369          *     };
23370          *
23371          *     $scope.addContact = function() {
23372          *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
23373          *     };
23374          *
23375          *     $scope.removeContact = function(contactToRemove) {
23376          *       var index = $scope.contacts.indexOf(contactToRemove);
23377          *       $scope.contacts.splice(index, 1);
23378          *     };
23379          *
23380          *     $scope.clearContact = function(contact) {
23381          *       contact.type = 'phone';
23382          *       contact.value = '';
23383          *     };
23384          *   }
23385          *  </file>
23386          *  <file name="protractor.js" type="protractor">
23387          *    it('should check controller', function() {
23388          *      var container = element(by.id('ctrl-exmpl'));
23389          *
23390          *      expect(container.element(by.model('name'))
23391          *          .getAttribute('value')).toBe('John Smith');
23392          *
23393          *      var firstRepeat =
23394          *          container.element(by.repeater('contact in contacts').row(0));
23395          *      var secondRepeat =
23396          *          container.element(by.repeater('contact in contacts').row(1));
23397          *
23398          *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23399          *          .toBe('408 555 1212');
23400          *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23401          *          .toBe('john.smith@example.org');
23402          *
23403          *      firstRepeat.element(by.buttonText('clear')).click();
23404          *
23405          *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23406          *          .toBe('');
23407          *
23408          *      container.element(by.buttonText('add')).click();
23409          *
23410          *      expect(container.element(by.repeater('contact in contacts').row(2))
23411          *          .element(by.model('contact.value'))
23412          *          .getAttribute('value'))
23413          *          .toBe('yourname@example.org');
23414          *    });
23415          *  </file>
23416          *</example>
23417
23418          */
23419         var ngControllerDirective = [function() {
23420           return {
23421             restrict: 'A',
23422             scope: true,
23423             controller: '@',
23424             priority: 500
23425           };
23426         }];
23427
23428         /**
23429          * @ngdoc directive
23430          * @name ngCsp
23431          *
23432          * @element html
23433          * @description
23434          *
23435          * Angular has some features that can break certain
23436          * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
23437          *
23438          * If you intend to implement these rules then you must tell Angular not to use these features.
23439          *
23440          * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
23441          *
23442          *
23443          * The following rules affect Angular:
23444          *
23445          * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
23446          * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
23447          * increase in the speed of evaluating Angular expressions.
23448          *
23449          * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
23450          * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
23451          * To make these directives work when a CSP rule is blocking inline styles, you must link to the
23452          * `angular-csp.css` in your HTML manually.
23453          *
23454          * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
23455          * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
23456          * however, triggers a CSP error to be logged in the console:
23457          *
23458          * ```
23459          * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
23460          * script in the following Content Security Policy directive: "default-src 'self'". Note that
23461          * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
23462          * ```
23463          *
23464          * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
23465          * directive on an element of the HTML document that appears before the `<script>` tag that loads
23466          * the `angular.js` file.
23467          *
23468          * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
23469          *
23470          * You can specify which of the CSP related Angular features should be deactivated by providing
23471          * a value for the `ng-csp` attribute. The options are as follows:
23472          *
23473          * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
23474          *
23475          * * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
23476          *
23477          * You can use these values in the following combinations:
23478          *
23479          *
23480          * * No declaration means that Angular will assume that you can do inline styles, but it will do
23481          * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous versions
23482          * of Angular.
23483          *
23484          * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
23485          * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous versions
23486          * of Angular.
23487          *
23488          * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can inject
23489          * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
23490          *
23491          * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
23492          * run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
23493          *
23494          * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
23495          * styles nor use eval, which is the same as an empty: ng-csp.
23496          * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
23497          *
23498          * @example
23499          * This example shows how to apply the `ngCsp` directive to the `html` tag.
23500            ```html
23501              <!doctype html>
23502              <html ng-app ng-csp>
23503              ...
23504              ...
23505              </html>
23506            ```
23507           * @example
23508               // Note: the suffix `.csp` in the example name triggers
23509               // csp mode in our http server!
23510               <example name="example.csp" module="cspExample" ng-csp="true">
23511                 <file name="index.html">
23512                   <div ng-controller="MainController as ctrl">
23513                     <div>
23514                       <button ng-click="ctrl.inc()" id="inc">Increment</button>
23515                       <span id="counter">
23516                         {{ctrl.counter}}
23517                       </span>
23518                     </div>
23519
23520                     <div>
23521                       <button ng-click="ctrl.evil()" id="evil">Evil</button>
23522                       <span id="evilError">
23523                         {{ctrl.evilError}}
23524                       </span>
23525                     </div>
23526                   </div>
23527                 </file>
23528                 <file name="script.js">
23529                    angular.module('cspExample', [])
23530                      .controller('MainController', function() {
23531                         this.counter = 0;
23532                         this.inc = function() {
23533                           this.counter++;
23534                         };
23535                         this.evil = function() {
23536                           // jshint evil:true
23537                           try {
23538                             eval('1+2');
23539                           } catch (e) {
23540                             this.evilError = e.message;
23541                           }
23542                         };
23543                       });
23544                 </file>
23545                 <file name="protractor.js" type="protractor">
23546                   var util, webdriver;
23547
23548                   var incBtn = element(by.id('inc'));
23549                   var counter = element(by.id('counter'));
23550                   var evilBtn = element(by.id('evil'));
23551                   var evilError = element(by.id('evilError'));
23552
23553                   function getAndClearSevereErrors() {
23554                     return browser.manage().logs().get('browser').then(function(browserLog) {
23555                       return browserLog.filter(function(logEntry) {
23556                         return logEntry.level.value > webdriver.logging.Level.WARNING.value;
23557                       });
23558                     });
23559                   }
23560
23561                   function clearErrors() {
23562                     getAndClearSevereErrors();
23563                   }
23564
23565                   function expectNoErrors() {
23566                     getAndClearSevereErrors().then(function(filteredLog) {
23567                       expect(filteredLog.length).toEqual(0);
23568                       if (filteredLog.length) {
23569                         console.log('browser console errors: ' + util.inspect(filteredLog));
23570                       }
23571                     });
23572                   }
23573
23574                   function expectError(regex) {
23575                     getAndClearSevereErrors().then(function(filteredLog) {
23576                       var found = false;
23577                       filteredLog.forEach(function(log) {
23578                         if (log.message.match(regex)) {
23579                           found = true;
23580                         }
23581                       });
23582                       if (!found) {
23583                         throw new Error('expected an error that matches ' + regex);
23584                       }
23585                     });
23586                   }
23587
23588                   beforeEach(function() {
23589                     util = require('util');
23590                     webdriver = require('protractor/node_modules/selenium-webdriver');
23591                   });
23592
23593                   // For now, we only test on Chrome,
23594                   // as Safari does not load the page with Protractor's injected scripts,
23595                   // and Firefox webdriver always disables content security policy (#6358)
23596                   if (browser.params.browser !== 'chrome') {
23597                     return;
23598                   }
23599
23600                   it('should not report errors when the page is loaded', function() {
23601                     // clear errors so we are not dependent on previous tests
23602                     clearErrors();
23603                     // Need to reload the page as the page is already loaded when
23604                     // we come here
23605                     browser.driver.getCurrentUrl().then(function(url) {
23606                       browser.get(url);
23607                     });
23608                     expectNoErrors();
23609                   });
23610
23611                   it('should evaluate expressions', function() {
23612                     expect(counter.getText()).toEqual('0');
23613                     incBtn.click();
23614                     expect(counter.getText()).toEqual('1');
23615                     expectNoErrors();
23616                   });
23617
23618                   it('should throw and report an error when using "eval"', function() {
23619                     evilBtn.click();
23620                     expect(evilError.getText()).toMatch(/Content Security Policy/);
23621                     expectError(/Content Security Policy/);
23622                   });
23623                 </file>
23624               </example>
23625           */
23626
23627         // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
23628         // bootstrap the system (before $parse is instantiated), for this reason we just have
23629         // the csp() fn that looks for the `ng-csp` attribute anywhere in the current doc
23630
23631         /**
23632          * @ngdoc directive
23633          * @name ngClick
23634          *
23635          * @description
23636          * The ngClick directive allows you to specify custom behavior when
23637          * an element is clicked.
23638          *
23639          * @element ANY
23640          * @priority 0
23641          * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
23642          * click. ({@link guide/expression#-event- Event object is available as `$event`})
23643          *
23644          * @example
23645            <example>
23646              <file name="index.html">
23647               <button ng-click="count = count + 1" ng-init="count=0">
23648                 Increment
23649               </button>
23650               <span>
23651                 count: {{count}}
23652               </span>
23653              </file>
23654              <file name="protractor.js" type="protractor">
23655                it('should check ng-click', function() {
23656                  expect(element(by.binding('count')).getText()).toMatch('0');
23657                  element(by.css('button')).click();
23658                  expect(element(by.binding('count')).getText()).toMatch('1');
23659                });
23660              </file>
23661            </example>
23662          */
23663         /*
23664          * A collection of directives that allows creation of custom event handlers that are defined as
23665          * angular expressions and are compiled and executed within the current scope.
23666          */
23667         var ngEventDirectives = {};
23668
23669         // For events that might fire synchronously during DOM manipulation
23670         // we need to execute their event handlers asynchronously using $evalAsync,
23671         // so that they are not executed in an inconsistent state.
23672         var forceAsyncEvents = {
23673           'blur': true,
23674           'focus': true
23675         };
23676         forEach(
23677           'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
23678           function(eventName) {
23679             var directiveName = directiveNormalize('ng-' + eventName);
23680             ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
23681               return {
23682                 restrict: 'A',
23683                 compile: function($element, attr) {
23684                   // We expose the powerful $event object on the scope that provides access to the Window,
23685                   // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
23686                   // checks at the cost of speed since event handler expressions are not executed as
23687                   // frequently as regular change detection.
23688                   var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
23689                   return function ngEventHandler(scope, element) {
23690                     element.on(eventName, function(event) {
23691                       var callback = function() {
23692                         fn(scope, {$event:event});
23693                       };
23694                       if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
23695                         scope.$evalAsync(callback);
23696                       } else {
23697                         scope.$apply(callback);
23698                       }
23699                     });
23700                   };
23701                 }
23702               };
23703             }];
23704           }
23705         );
23706
23707         /**
23708          * @ngdoc directive
23709          * @name ngDblclick
23710          *
23711          * @description
23712          * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
23713          *
23714          * @element ANY
23715          * @priority 0
23716          * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
23717          * a dblclick. (The Event object is available as `$event`)
23718          *
23719          * @example
23720            <example>
23721              <file name="index.html">
23722               <button ng-dblclick="count = count + 1" ng-init="count=0">
23723                 Increment (on double click)
23724               </button>
23725               count: {{count}}
23726              </file>
23727            </example>
23728          */
23729
23730
23731         /**
23732          * @ngdoc directive
23733          * @name ngMousedown
23734          *
23735          * @description
23736          * The ngMousedown directive allows you to specify custom behavior on mousedown event.
23737          *
23738          * @element ANY
23739          * @priority 0
23740          * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
23741          * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
23742          *
23743          * @example
23744            <example>
23745              <file name="index.html">
23746               <button ng-mousedown="count = count + 1" ng-init="count=0">
23747                 Increment (on mouse down)
23748               </button>
23749               count: {{count}}
23750              </file>
23751            </example>
23752          */
23753
23754
23755         /**
23756          * @ngdoc directive
23757          * @name ngMouseup
23758          *
23759          * @description
23760          * Specify custom behavior on mouseup event.
23761          *
23762          * @element ANY
23763          * @priority 0
23764          * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
23765          * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
23766          *
23767          * @example
23768            <example>
23769              <file name="index.html">
23770               <button ng-mouseup="count = count + 1" ng-init="count=0">
23771                 Increment (on mouse up)
23772               </button>
23773               count: {{count}}
23774              </file>
23775            </example>
23776          */
23777
23778         /**
23779          * @ngdoc directive
23780          * @name ngMouseover
23781          *
23782          * @description
23783          * Specify custom behavior on mouseover event.
23784          *
23785          * @element ANY
23786          * @priority 0
23787          * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
23788          * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
23789          *
23790          * @example
23791            <example>
23792              <file name="index.html">
23793               <button ng-mouseover="count = count + 1" ng-init="count=0">
23794                 Increment (when mouse is over)
23795               </button>
23796               count: {{count}}
23797              </file>
23798            </example>
23799          */
23800
23801
23802         /**
23803          * @ngdoc directive
23804          * @name ngMouseenter
23805          *
23806          * @description
23807          * Specify custom behavior on mouseenter event.
23808          *
23809          * @element ANY
23810          * @priority 0
23811          * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
23812          * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
23813          *
23814          * @example
23815            <example>
23816              <file name="index.html">
23817               <button ng-mouseenter="count = count + 1" ng-init="count=0">
23818                 Increment (when mouse enters)
23819               </button>
23820               count: {{count}}
23821              </file>
23822            </example>
23823          */
23824
23825
23826         /**
23827          * @ngdoc directive
23828          * @name ngMouseleave
23829          *
23830          * @description
23831          * Specify custom behavior on mouseleave event.
23832          *
23833          * @element ANY
23834          * @priority 0
23835          * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
23836          * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
23837          *
23838          * @example
23839            <example>
23840              <file name="index.html">
23841               <button ng-mouseleave="count = count + 1" ng-init="count=0">
23842                 Increment (when mouse leaves)
23843               </button>
23844               count: {{count}}
23845              </file>
23846            </example>
23847          */
23848
23849
23850         /**
23851          * @ngdoc directive
23852          * @name ngMousemove
23853          *
23854          * @description
23855          * Specify custom behavior on mousemove event.
23856          *
23857          * @element ANY
23858          * @priority 0
23859          * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
23860          * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
23861          *
23862          * @example
23863            <example>
23864              <file name="index.html">
23865               <button ng-mousemove="count = count + 1" ng-init="count=0">
23866                 Increment (when mouse moves)
23867               </button>
23868               count: {{count}}
23869              </file>
23870            </example>
23871          */
23872
23873
23874         /**
23875          * @ngdoc directive
23876          * @name ngKeydown
23877          *
23878          * @description
23879          * Specify custom behavior on keydown event.
23880          *
23881          * @element ANY
23882          * @priority 0
23883          * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
23884          * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23885          *
23886          * @example
23887            <example>
23888              <file name="index.html">
23889               <input ng-keydown="count = count + 1" ng-init="count=0">
23890               key down count: {{count}}
23891              </file>
23892            </example>
23893          */
23894
23895
23896         /**
23897          * @ngdoc directive
23898          * @name ngKeyup
23899          *
23900          * @description
23901          * Specify custom behavior on keyup event.
23902          *
23903          * @element ANY
23904          * @priority 0
23905          * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
23906          * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23907          *
23908          * @example
23909            <example>
23910              <file name="index.html">
23911                <p>Typing in the input box below updates the key count</p>
23912                <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
23913
23914                <p>Typing in the input box below updates the keycode</p>
23915                <input ng-keyup="event=$event">
23916                <p>event keyCode: {{ event.keyCode }}</p>
23917                <p>event altKey: {{ event.altKey }}</p>
23918              </file>
23919            </example>
23920          */
23921
23922
23923         /**
23924          * @ngdoc directive
23925          * @name ngKeypress
23926          *
23927          * @description
23928          * Specify custom behavior on keypress event.
23929          *
23930          * @element ANY
23931          * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
23932          * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
23933          * and can be interrogated for keyCode, altKey, etc.)
23934          *
23935          * @example
23936            <example>
23937              <file name="index.html">
23938               <input ng-keypress="count = count + 1" ng-init="count=0">
23939               key press count: {{count}}
23940              </file>
23941            </example>
23942          */
23943
23944
23945         /**
23946          * @ngdoc directive
23947          * @name ngSubmit
23948          *
23949          * @description
23950          * Enables binding angular expressions to onsubmit events.
23951          *
23952          * Additionally it prevents the default action (which for form means sending the request to the
23953          * server and reloading the current page), but only if the form does not contain `action`,
23954          * `data-action`, or `x-action` attributes.
23955          *
23956          * <div class="alert alert-warning">
23957          * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
23958          * `ngSubmit` handlers together. See the
23959          * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
23960          * for a detailed discussion of when `ngSubmit` may be triggered.
23961          * </div>
23962          *
23963          * @element form
23964          * @priority 0
23965          * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
23966          * ({@link guide/expression#-event- Event object is available as `$event`})
23967          *
23968          * @example
23969            <example module="submitExample">
23970              <file name="index.html">
23971               <script>
23972                 angular.module('submitExample', [])
23973                   .controller('ExampleController', ['$scope', function($scope) {
23974                     $scope.list = [];
23975                     $scope.text = 'hello';
23976                     $scope.submit = function() {
23977                       if ($scope.text) {
23978                         $scope.list.push(this.text);
23979                         $scope.text = '';
23980                       }
23981                     };
23982                   }]);
23983               </script>
23984               <form ng-submit="submit()" ng-controller="ExampleController">
23985                 Enter text and hit enter:
23986                 <input type="text" ng-model="text" name="text" />
23987                 <input type="submit" id="submit" value="Submit" />
23988                 <pre>list={{list}}</pre>
23989               </form>
23990              </file>
23991              <file name="protractor.js" type="protractor">
23992                it('should check ng-submit', function() {
23993                  expect(element(by.binding('list')).getText()).toBe('list=[]');
23994                  element(by.css('#submit')).click();
23995                  expect(element(by.binding('list')).getText()).toContain('hello');
23996                  expect(element(by.model('text')).getAttribute('value')).toBe('');
23997                });
23998                it('should ignore empty strings', function() {
23999                  expect(element(by.binding('list')).getText()).toBe('list=[]');
24000                  element(by.css('#submit')).click();
24001                  element(by.css('#submit')).click();
24002                  expect(element(by.binding('list')).getText()).toContain('hello');
24003                 });
24004              </file>
24005            </example>
24006          */
24007
24008         /**
24009          * @ngdoc directive
24010          * @name ngFocus
24011          *
24012          * @description
24013          * Specify custom behavior on focus event.
24014          *
24015          * Note: As the `focus` event is executed synchronously when calling `input.focus()`
24016          * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
24017          * during an `$apply` to ensure a consistent state.
24018          *
24019          * @element window, input, select, textarea, a
24020          * @priority 0
24021          * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
24022          * focus. ({@link guide/expression#-event- Event object is available as `$event`})
24023          *
24024          * @example
24025          * See {@link ng.directive:ngClick ngClick}
24026          */
24027
24028         /**
24029          * @ngdoc directive
24030          * @name ngBlur
24031          *
24032          * @description
24033          * Specify custom behavior on blur event.
24034          *
24035          * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
24036          * an element has lost focus.
24037          *
24038          * Note: As the `blur` event is executed synchronously also during DOM manipulations
24039          * (e.g. removing a focussed input),
24040          * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
24041          * during an `$apply` to ensure a consistent state.
24042          *
24043          * @element window, input, select, textarea, a
24044          * @priority 0
24045          * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
24046          * blur. ({@link guide/expression#-event- Event object is available as `$event`})
24047          *
24048          * @example
24049          * See {@link ng.directive:ngClick ngClick}
24050          */
24051
24052         /**
24053          * @ngdoc directive
24054          * @name ngCopy
24055          *
24056          * @description
24057          * Specify custom behavior on copy event.
24058          *
24059          * @element window, input, select, textarea, a
24060          * @priority 0
24061          * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
24062          * copy. ({@link guide/expression#-event- Event object is available as `$event`})
24063          *
24064          * @example
24065            <example>
24066              <file name="index.html">
24067               <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
24068               copied: {{copied}}
24069              </file>
24070            </example>
24071          */
24072
24073         /**
24074          * @ngdoc directive
24075          * @name ngCut
24076          *
24077          * @description
24078          * Specify custom behavior on cut event.
24079          *
24080          * @element window, input, select, textarea, a
24081          * @priority 0
24082          * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
24083          * cut. ({@link guide/expression#-event- Event object is available as `$event`})
24084          *
24085          * @example
24086            <example>
24087              <file name="index.html">
24088               <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
24089               cut: {{cut}}
24090              </file>
24091            </example>
24092          */
24093
24094         /**
24095          * @ngdoc directive
24096          * @name ngPaste
24097          *
24098          * @description
24099          * Specify custom behavior on paste event.
24100          *
24101          * @element window, input, select, textarea, a
24102          * @priority 0
24103          * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
24104          * paste. ({@link guide/expression#-event- Event object is available as `$event`})
24105          *
24106          * @example
24107            <example>
24108              <file name="index.html">
24109               <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
24110               pasted: {{paste}}
24111              </file>
24112            </example>
24113          */
24114
24115         /**
24116          * @ngdoc directive
24117          * @name ngIf
24118          * @restrict A
24119          * @multiElement
24120          *
24121          * @description
24122          * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
24123          * {expression}. If the expression assigned to `ngIf` evaluates to a false
24124          * value then the element is removed from the DOM, otherwise a clone of the
24125          * element is reinserted into the DOM.
24126          *
24127          * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
24128          * element in the DOM rather than changing its visibility via the `display` css property.  A common
24129          * case when this difference is significant is when using css selectors that rely on an element's
24130          * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
24131          *
24132          * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
24133          * is created when the element is restored.  The scope created within `ngIf` inherits from
24134          * its parent scope using
24135          * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
24136          * An important implication of this is if `ngModel` is used within `ngIf` to bind to
24137          * a javascript primitive defined in the parent scope. In this case any modifications made to the
24138          * variable within the child scope will override (hide) the value in the parent scope.
24139          *
24140          * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
24141          * is if an element's class attribute is directly modified after it's compiled, using something like
24142          * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
24143          * the added class will be lost because the original compiled state is used to regenerate the element.
24144          *
24145          * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
24146          * and `leave` effects.
24147          *
24148          * @animations
24149          * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
24150          * leave - happens just before the `ngIf` contents are removed from the DOM
24151          *
24152          * @element ANY
24153          * @scope
24154          * @priority 600
24155          * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
24156          *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
24157          *     element is added to the DOM tree.
24158          *
24159          * @example
24160           <example module="ngAnimate" deps="angular-animate.js" animations="true">
24161             <file name="index.html">
24162               <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
24163               Show when checked:
24164               <span ng-if="checked" class="animate-if">
24165                 This is removed when the checkbox is unchecked.
24166               </span>
24167             </file>
24168             <file name="animations.css">
24169               .animate-if {
24170                 background:white;
24171                 border:1px solid black;
24172                 padding:10px;
24173               }
24174
24175               .animate-if.ng-enter, .animate-if.ng-leave {
24176                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24177               }
24178
24179               .animate-if.ng-enter,
24180               .animate-if.ng-leave.ng-leave-active {
24181                 opacity:0;
24182               }
24183
24184               .animate-if.ng-leave,
24185               .animate-if.ng-enter.ng-enter-active {
24186                 opacity:1;
24187               }
24188             </file>
24189           </example>
24190          */
24191         var ngIfDirective = ['$animate', function($animate) {
24192           return {
24193             multiElement: true,
24194             transclude: 'element',
24195             priority: 600,
24196             terminal: true,
24197             restrict: 'A',
24198             $$tlb: true,
24199             link: function($scope, $element, $attr, ctrl, $transclude) {
24200                 var block, childScope, previousElements;
24201                 $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
24202
24203                   if (value) {
24204                     if (!childScope) {
24205                       $transclude(function(clone, newScope) {
24206                         childScope = newScope;
24207                         clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
24208                         // Note: We only need the first/last node of the cloned nodes.
24209                         // However, we need to keep the reference to the jqlite wrapper as it might be changed later
24210                         // by a directive with templateUrl when its template arrives.
24211                         block = {
24212                           clone: clone
24213                         };
24214                         $animate.enter(clone, $element.parent(), $element);
24215                       });
24216                     }
24217                   } else {
24218                     if (previousElements) {
24219                       previousElements.remove();
24220                       previousElements = null;
24221                     }
24222                     if (childScope) {
24223                       childScope.$destroy();
24224                       childScope = null;
24225                     }
24226                     if (block) {
24227                       previousElements = getBlockNodes(block.clone);
24228                       $animate.leave(previousElements).then(function() {
24229                         previousElements = null;
24230                       });
24231                       block = null;
24232                     }
24233                   }
24234                 });
24235             }
24236           };
24237         }];
24238
24239         /**
24240          * @ngdoc directive
24241          * @name ngInclude
24242          * @restrict ECA
24243          *
24244          * @description
24245          * Fetches, compiles and includes an external HTML fragment.
24246          *
24247          * By default, the template URL is restricted to the same domain and protocol as the
24248          * application document. This is done by calling {@link $sce#getTrustedResourceUrl
24249          * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
24250          * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
24251          * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
24252          * ng.$sce Strict Contextual Escaping}.
24253          *
24254          * In addition, the browser's
24255          * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
24256          * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
24257          * policy may further restrict whether the template is successfully loaded.
24258          * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
24259          * access on some browsers.
24260          *
24261          * @animations
24262          * enter - animation is used to bring new content into the browser.
24263          * leave - animation is used to animate existing content away.
24264          *
24265          * The enter and leave animation occur concurrently.
24266          *
24267          * @scope
24268          * @priority 400
24269          *
24270          * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
24271          *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
24272          * @param {string=} onload Expression to evaluate when a new partial is loaded.
24273          *                  <div class="alert alert-warning">
24274          *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
24275          *                  a function with the name on the window element, which will usually throw a
24276          *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
24277          *                  different form that {@link guide/directive#normalization matches} `onload`.
24278          *                  </div>
24279            *
24280          * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
24281          *                  $anchorScroll} to scroll the viewport after the content is loaded.
24282          *
24283          *                  - If the attribute is not set, disable scrolling.
24284          *                  - If the attribute is set without value, enable scrolling.
24285          *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
24286          *
24287          * @example
24288           <example module="includeExample" deps="angular-animate.js" animations="true">
24289             <file name="index.html">
24290              <div ng-controller="ExampleController">
24291                <select ng-model="template" ng-options="t.name for t in templates">
24292                 <option value="">(blank)</option>
24293                </select>
24294                url of the template: <code>{{template.url}}</code>
24295                <hr/>
24296                <div class="slide-animate-container">
24297                  <div class="slide-animate" ng-include="template.url"></div>
24298                </div>
24299              </div>
24300             </file>
24301             <file name="script.js">
24302               angular.module('includeExample', ['ngAnimate'])
24303                 .controller('ExampleController', ['$scope', function($scope) {
24304                   $scope.templates =
24305                     [ { name: 'template1.html', url: 'template1.html'},
24306                       { name: 'template2.html', url: 'template2.html'} ];
24307                   $scope.template = $scope.templates[0];
24308                 }]);
24309              </file>
24310             <file name="template1.html">
24311               Content of template1.html
24312             </file>
24313             <file name="template2.html">
24314               Content of template2.html
24315             </file>
24316             <file name="animations.css">
24317               .slide-animate-container {
24318                 position:relative;
24319                 background:white;
24320                 border:1px solid black;
24321                 height:40px;
24322                 overflow:hidden;
24323               }
24324
24325               .slide-animate {
24326                 padding:10px;
24327               }
24328
24329               .slide-animate.ng-enter, .slide-animate.ng-leave {
24330                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24331
24332                 position:absolute;
24333                 top:0;
24334                 left:0;
24335                 right:0;
24336                 bottom:0;
24337                 display:block;
24338                 padding:10px;
24339               }
24340
24341               .slide-animate.ng-enter {
24342                 top:-50px;
24343               }
24344               .slide-animate.ng-enter.ng-enter-active {
24345                 top:0;
24346               }
24347
24348               .slide-animate.ng-leave {
24349                 top:0;
24350               }
24351               .slide-animate.ng-leave.ng-leave-active {
24352                 top:50px;
24353               }
24354             </file>
24355             <file name="protractor.js" type="protractor">
24356               var templateSelect = element(by.model('template'));
24357               var includeElem = element(by.css('[ng-include]'));
24358
24359               it('should load template1.html', function() {
24360                 expect(includeElem.getText()).toMatch(/Content of template1.html/);
24361               });
24362
24363               it('should load template2.html', function() {
24364                 if (browser.params.browser == 'firefox') {
24365                   // Firefox can't handle using selects
24366                   // See https://github.com/angular/protractor/issues/480
24367                   return;
24368                 }
24369                 templateSelect.click();
24370                 templateSelect.all(by.css('option')).get(2).click();
24371                 expect(includeElem.getText()).toMatch(/Content of template2.html/);
24372               });
24373
24374               it('should change to blank', function() {
24375                 if (browser.params.browser == 'firefox') {
24376                   // Firefox can't handle using selects
24377                   return;
24378                 }
24379                 templateSelect.click();
24380                 templateSelect.all(by.css('option')).get(0).click();
24381                 expect(includeElem.isPresent()).toBe(false);
24382               });
24383             </file>
24384           </example>
24385          */
24386
24387
24388         /**
24389          * @ngdoc event
24390          * @name ngInclude#$includeContentRequested
24391          * @eventType emit on the scope ngInclude was declared in
24392          * @description
24393          * Emitted every time the ngInclude content is requested.
24394          *
24395          * @param {Object} angularEvent Synthetic event object.
24396          * @param {String} src URL of content to load.
24397          */
24398
24399
24400         /**
24401          * @ngdoc event
24402          * @name ngInclude#$includeContentLoaded
24403          * @eventType emit on the current ngInclude scope
24404          * @description
24405          * Emitted every time the ngInclude content is reloaded.
24406          *
24407          * @param {Object} angularEvent Synthetic event object.
24408          * @param {String} src URL of content to load.
24409          */
24410
24411
24412         /**
24413          * @ngdoc event
24414          * @name ngInclude#$includeContentError
24415          * @eventType emit on the scope ngInclude was declared in
24416          * @description
24417          * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
24418          *
24419          * @param {Object} angularEvent Synthetic event object.
24420          * @param {String} src URL of content to load.
24421          */
24422         var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
24423                           function($templateRequest,   $anchorScroll,   $animate) {
24424           return {
24425             restrict: 'ECA',
24426             priority: 400,
24427             terminal: true,
24428             transclude: 'element',
24429             controller: angular.noop,
24430             compile: function(element, attr) {
24431               var srcExp = attr.ngInclude || attr.src,
24432                   onloadExp = attr.onload || '',
24433                   autoScrollExp = attr.autoscroll;
24434
24435               return function(scope, $element, $attr, ctrl, $transclude) {
24436                 var changeCounter = 0,
24437                     currentScope,
24438                     previousElement,
24439                     currentElement;
24440
24441                 var cleanupLastIncludeContent = function() {
24442                   if (previousElement) {
24443                     previousElement.remove();
24444                     previousElement = null;
24445                   }
24446                   if (currentScope) {
24447                     currentScope.$destroy();
24448                     currentScope = null;
24449                   }
24450                   if (currentElement) {
24451                     $animate.leave(currentElement).then(function() {
24452                       previousElement = null;
24453                     });
24454                     previousElement = currentElement;
24455                     currentElement = null;
24456                   }
24457                 };
24458
24459                 scope.$watch(srcExp, function ngIncludeWatchAction(src) {
24460                   var afterAnimation = function() {
24461                     if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
24462                       $anchorScroll();
24463                     }
24464                   };
24465                   var thisChangeId = ++changeCounter;
24466
24467                   if (src) {
24468                     //set the 2nd param to true to ignore the template request error so that the inner
24469                     //contents and scope can be cleaned up.
24470                     $templateRequest(src, true).then(function(response) {
24471                       if (thisChangeId !== changeCounter) return;
24472                       var newScope = scope.$new();
24473                       ctrl.template = response;
24474
24475                       // Note: This will also link all children of ng-include that were contained in the original
24476                       // html. If that content contains controllers, ... they could pollute/change the scope.
24477                       // However, using ng-include on an element with additional content does not make sense...
24478                       // Note: We can't remove them in the cloneAttchFn of $transclude as that
24479                       // function is called before linking the content, which would apply child
24480                       // directives to non existing elements.
24481                       var clone = $transclude(newScope, function(clone) {
24482                         cleanupLastIncludeContent();
24483                         $animate.enter(clone, null, $element).then(afterAnimation);
24484                       });
24485
24486                       currentScope = newScope;
24487                       currentElement = clone;
24488
24489                       currentScope.$emit('$includeContentLoaded', src);
24490                       scope.$eval(onloadExp);
24491                     }, function() {
24492                       if (thisChangeId === changeCounter) {
24493                         cleanupLastIncludeContent();
24494                         scope.$emit('$includeContentError', src);
24495                       }
24496                     });
24497                     scope.$emit('$includeContentRequested', src);
24498                   } else {
24499                     cleanupLastIncludeContent();
24500                     ctrl.template = null;
24501                   }
24502                 });
24503               };
24504             }
24505           };
24506         }];
24507
24508         // This directive is called during the $transclude call of the first `ngInclude` directive.
24509         // It will replace and compile the content of the element with the loaded template.
24510         // We need this directive so that the element content is already filled when
24511         // the link function of another directive on the same element as ngInclude
24512         // is called.
24513         var ngIncludeFillContentDirective = ['$compile',
24514           function($compile) {
24515             return {
24516               restrict: 'ECA',
24517               priority: -400,
24518               require: 'ngInclude',
24519               link: function(scope, $element, $attr, ctrl) {
24520                 if (/SVG/.test($element[0].toString())) {
24521                   // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
24522                   // support innerHTML, so detect this here and try to generate the contents
24523                   // specially.
24524                   $element.empty();
24525                   $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
24526                       function namespaceAdaptedClone(clone) {
24527                     $element.append(clone);
24528                   }, {futureParentElement: $element});
24529                   return;
24530                 }
24531
24532                 $element.html(ctrl.template);
24533                 $compile($element.contents())(scope);
24534               }
24535             };
24536           }];
24537
24538         /**
24539          * @ngdoc directive
24540          * @name ngInit
24541          * @restrict AC
24542          *
24543          * @description
24544          * The `ngInit` directive allows you to evaluate an expression in the
24545          * current scope.
24546          *
24547          * <div class="alert alert-danger">
24548          * This directive can be abused to add unnecessary amounts of logic into your templates.
24549          * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
24550          * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
24551          * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
24552          * rather than `ngInit` to initialize values on a scope.
24553          * </div>
24554          *
24555          * <div class="alert alert-warning">
24556          * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
24557          * sure you have parentheses to ensure correct operator precedence:
24558          * <pre class="prettyprint">
24559          * `<div ng-init="test1 = ($index | toString)"></div>`
24560          * </pre>
24561          * </div>
24562          *
24563          * @priority 450
24564          *
24565          * @element ANY
24566          * @param {expression} ngInit {@link guide/expression Expression} to eval.
24567          *
24568          * @example
24569            <example module="initExample">
24570              <file name="index.html">
24571            <script>
24572              angular.module('initExample', [])
24573                .controller('ExampleController', ['$scope', function($scope) {
24574                  $scope.list = [['a', 'b'], ['c', 'd']];
24575                }]);
24576            </script>
24577            <div ng-controller="ExampleController">
24578              <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
24579                <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
24580                   <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
24581                </div>
24582              </div>
24583            </div>
24584              </file>
24585              <file name="protractor.js" type="protractor">
24586                it('should alias index positions', function() {
24587                  var elements = element.all(by.css('.example-init'));
24588                  expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
24589                  expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
24590                  expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
24591                  expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
24592                });
24593              </file>
24594            </example>
24595          */
24596         var ngInitDirective = ngDirective({
24597           priority: 450,
24598           compile: function() {
24599             return {
24600               pre: function(scope, element, attrs) {
24601                 scope.$eval(attrs.ngInit);
24602               }
24603             };
24604           }
24605         });
24606
24607         /**
24608          * @ngdoc directive
24609          * @name ngList
24610          *
24611          * @description
24612          * Text input that converts between a delimited string and an array of strings. The default
24613          * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
24614          * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
24615          *
24616          * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
24617          * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
24618          *   list item is respected. This implies that the user of the directive is responsible for
24619          *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
24620          *   tab or newline character.
24621          * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
24622          *   when joining the list items back together) and whitespace around each list item is stripped
24623          *   before it is added to the model.
24624          *
24625          * ### Example with Validation
24626          *
24627          * <example name="ngList-directive" module="listExample">
24628          *   <file name="app.js">
24629          *      angular.module('listExample', [])
24630          *        .controller('ExampleController', ['$scope', function($scope) {
24631          *          $scope.names = ['morpheus', 'neo', 'trinity'];
24632          *        }]);
24633          *   </file>
24634          *   <file name="index.html">
24635          *    <form name="myForm" ng-controller="ExampleController">
24636          *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
24637          *      <span role="alert">
24638          *        <span class="error" ng-show="myForm.namesInput.$error.required">
24639          *        Required!</span>
24640          *      </span>
24641          *      <br>
24642          *      <tt>names = {{names}}</tt><br/>
24643          *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
24644          *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
24645          *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
24646          *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
24647          *     </form>
24648          *   </file>
24649          *   <file name="protractor.js" type="protractor">
24650          *     var listInput = element(by.model('names'));
24651          *     var names = element(by.exactBinding('names'));
24652          *     var valid = element(by.binding('myForm.namesInput.$valid'));
24653          *     var error = element(by.css('span.error'));
24654          *
24655          *     it('should initialize to model', function() {
24656          *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
24657          *       expect(valid.getText()).toContain('true');
24658          *       expect(error.getCssValue('display')).toBe('none');
24659          *     });
24660          *
24661          *     it('should be invalid if empty', function() {
24662          *       listInput.clear();
24663          *       listInput.sendKeys('');
24664          *
24665          *       expect(names.getText()).toContain('');
24666          *       expect(valid.getText()).toContain('false');
24667          *       expect(error.getCssValue('display')).not.toBe('none');
24668          *     });
24669          *   </file>
24670          * </example>
24671          *
24672          * ### Example - splitting on newline
24673          * <example name="ngList-directive-newlines">
24674          *   <file name="index.html">
24675          *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
24676          *    <pre>{{ list | json }}</pre>
24677          *   </file>
24678          *   <file name="protractor.js" type="protractor">
24679          *     it("should split the text by newlines", function() {
24680          *       var listInput = element(by.model('list'));
24681          *       var output = element(by.binding('list | json'));
24682          *       listInput.sendKeys('abc\ndef\nghi');
24683          *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
24684          *     });
24685          *   </file>
24686          * </example>
24687          *
24688          * @element input
24689          * @param {string=} ngList optional delimiter that should be used to split the value.
24690          */
24691         var ngListDirective = function() {
24692           return {
24693             restrict: 'A',
24694             priority: 100,
24695             require: 'ngModel',
24696             link: function(scope, element, attr, ctrl) {
24697               // We want to control whitespace trimming so we use this convoluted approach
24698               // to access the ngList attribute, which doesn't pre-trim the attribute
24699               var ngList = element.attr(attr.$attr.ngList) || ', ';
24700               var trimValues = attr.ngTrim !== 'false';
24701               var separator = trimValues ? trim(ngList) : ngList;
24702
24703               var parse = function(viewValue) {
24704                 // If the viewValue is invalid (say required but empty) it will be `undefined`
24705                 if (isUndefined(viewValue)) return;
24706
24707                 var list = [];
24708
24709                 if (viewValue) {
24710                   forEach(viewValue.split(separator), function(value) {
24711                     if (value) list.push(trimValues ? trim(value) : value);
24712                   });
24713                 }
24714
24715                 return list;
24716               };
24717
24718               ctrl.$parsers.push(parse);
24719               ctrl.$formatters.push(function(value) {
24720                 if (isArray(value)) {
24721                   return value.join(ngList);
24722                 }
24723
24724                 return undefined;
24725               });
24726
24727               // Override the standard $isEmpty because an empty array means the input is empty.
24728               ctrl.$isEmpty = function(value) {
24729                 return !value || !value.length;
24730               };
24731             }
24732           };
24733         };
24734
24735         /* global VALID_CLASS: true,
24736           INVALID_CLASS: true,
24737           PRISTINE_CLASS: true,
24738           DIRTY_CLASS: true,
24739           UNTOUCHED_CLASS: true,
24740           TOUCHED_CLASS: true,
24741         */
24742
24743         var VALID_CLASS = 'ng-valid',
24744             INVALID_CLASS = 'ng-invalid',
24745             PRISTINE_CLASS = 'ng-pristine',
24746             DIRTY_CLASS = 'ng-dirty',
24747             UNTOUCHED_CLASS = 'ng-untouched',
24748             TOUCHED_CLASS = 'ng-touched',
24749             PENDING_CLASS = 'ng-pending';
24750
24751         var ngModelMinErr = minErr('ngModel');
24752
24753         /**
24754          * @ngdoc type
24755          * @name ngModel.NgModelController
24756          *
24757          * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
24758          * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
24759          * is set.
24760          * @property {*} $modelValue The value in the model that the control is bound to.
24761          * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
24762                the control reads value from the DOM. The functions are called in array order, each passing
24763                its return value through to the next. The last return value is forwarded to the
24764                {@link ngModel.NgModelController#$validators `$validators`} collection.
24765
24766         Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
24767         `$viewValue`}.
24768
24769         Returning `undefined` from a parser means a parse error occurred. In that case,
24770         no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
24771         will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
24772         is set to `true`. The parse error is stored in `ngModel.$error.parse`.
24773
24774          *
24775          * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
24776                the model value changes. The functions are called in reverse array order, each passing the value through to the
24777                next. The last return value is used as the actual DOM value.
24778                Used to format / convert values for display in the control.
24779          * ```js
24780          * function formatter(value) {
24781          *   if (value) {
24782          *     return value.toUpperCase();
24783          *   }
24784          * }
24785          * ngModel.$formatters.push(formatter);
24786          * ```
24787          *
24788          * @property {Object.<string, function>} $validators A collection of validators that are applied
24789          *      whenever the model value changes. The key value within the object refers to the name of the
24790          *      validator while the function refers to the validation operation. The validation operation is
24791          *      provided with the model value as an argument and must return a true or false value depending
24792          *      on the response of that validation.
24793          *
24794          * ```js
24795          * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
24796          *   var value = modelValue || viewValue;
24797          *   return /[0-9]+/.test(value) &&
24798          *          /[a-z]+/.test(value) &&
24799          *          /[A-Z]+/.test(value) &&
24800          *          /\W+/.test(value);
24801          * };
24802          * ```
24803          *
24804          * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
24805          *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
24806          *      is expected to return a promise when it is run during the model validation process. Once the promise
24807          *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
24808          *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
24809          *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
24810          *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
24811          *      will only run once all synchronous validators have passed.
24812          *
24813          * Please note that if $http is used then it is important that the server returns a success HTTP response code
24814          * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
24815          *
24816          * ```js
24817          * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
24818          *   var value = modelValue || viewValue;
24819          *
24820          *   // Lookup user by username
24821          *   return $http.get('/api/users/' + value).
24822          *      then(function resolved() {
24823          *        //username exists, this means validation fails
24824          *        return $q.reject('exists');
24825          *      }, function rejected() {
24826          *        //username does not exist, therefore this validation passes
24827          *        return true;
24828          *      });
24829          * };
24830          * ```
24831          *
24832          * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
24833          *     view value has changed. It is called with no arguments, and its return value is ignored.
24834          *     This can be used in place of additional $watches against the model value.
24835          *
24836          * @property {Object} $error An object hash with all failing validator ids as keys.
24837          * @property {Object} $pending An object hash with all pending validator ids as keys.
24838          *
24839          * @property {boolean} $untouched True if control has not lost focus yet.
24840          * @property {boolean} $touched True if control has lost focus.
24841          * @property {boolean} $pristine True if user has not interacted with the control yet.
24842          * @property {boolean} $dirty True if user has already interacted with the control.
24843          * @property {boolean} $valid True if there is no error.
24844          * @property {boolean} $invalid True if at least one error on the control.
24845          * @property {string} $name The name attribute of the control.
24846          *
24847          * @description
24848          *
24849          * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
24850          * The controller contains services for data-binding, validation, CSS updates, and value formatting
24851          * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
24852          * listening to DOM events.
24853          * Such DOM related logic should be provided by other directives which make use of
24854          * `NgModelController` for data-binding to control elements.
24855          * Angular provides this DOM logic for most {@link input `input`} elements.
24856          * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
24857          * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
24858          *
24859          * @example
24860          * ### Custom Control Example
24861          * This example shows how to use `NgModelController` with a custom control to achieve
24862          * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
24863          * collaborate together to achieve the desired result.
24864          *
24865          * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
24866          * contents be edited in place by the user.
24867          *
24868          * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
24869          * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
24870          * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
24871          * that content using the `$sce` service.
24872          *
24873          * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
24874             <file name="style.css">
24875               [contenteditable] {
24876                 border: 1px solid black;
24877                 background-color: white;
24878                 min-height: 20px;
24879               }
24880
24881               .ng-invalid {
24882                 border: 1px solid red;
24883               }
24884
24885             </file>
24886             <file name="script.js">
24887               angular.module('customControl', ['ngSanitize']).
24888                 directive('contenteditable', ['$sce', function($sce) {
24889                   return {
24890                     restrict: 'A', // only activate on element attribute
24891                     require: '?ngModel', // get a hold of NgModelController
24892                     link: function(scope, element, attrs, ngModel) {
24893                       if (!ngModel) return; // do nothing if no ng-model
24894
24895                       // Specify how UI should be updated
24896                       ngModel.$render = function() {
24897                         element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
24898                       };
24899
24900                       // Listen for change events to enable binding
24901                       element.on('blur keyup change', function() {
24902                         scope.$evalAsync(read);
24903                       });
24904                       read(); // initialize
24905
24906                       // Write data to the model
24907                       function read() {
24908                         var html = element.html();
24909                         // When we clear the content editable the browser leaves a <br> behind
24910                         // If strip-br attribute is provided then we strip this out
24911                         if ( attrs.stripBr && html == '<br>' ) {
24912                           html = '';
24913                         }
24914                         ngModel.$setViewValue(html);
24915                       }
24916                     }
24917                   };
24918                 }]);
24919             </file>
24920             <file name="index.html">
24921               <form name="myForm">
24922                <div contenteditable
24923                     name="myWidget" ng-model="userContent"
24924                     strip-br="true"
24925                     required>Change me!</div>
24926                 <span ng-show="myForm.myWidget.$error.required">Required!</span>
24927                <hr>
24928                <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
24929               </form>
24930             </file>
24931             <file name="protractor.js" type="protractor">
24932             it('should data-bind and become invalid', function() {
24933               if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
24934                 // SafariDriver can't handle contenteditable
24935                 // and Firefox driver can't clear contenteditables very well
24936                 return;
24937               }
24938               var contentEditable = element(by.css('[contenteditable]'));
24939               var content = 'Change me!';
24940
24941               expect(contentEditable.getText()).toEqual(content);
24942
24943               contentEditable.clear();
24944               contentEditable.sendKeys(protractor.Key.BACK_SPACE);
24945               expect(contentEditable.getText()).toEqual('');
24946               expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
24947             });
24948             </file>
24949          * </example>
24950          *
24951          *
24952          */
24953         var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
24954             function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
24955           this.$viewValue = Number.NaN;
24956           this.$modelValue = Number.NaN;
24957           this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
24958           this.$validators = {};
24959           this.$asyncValidators = {};
24960           this.$parsers = [];
24961           this.$formatters = [];
24962           this.$viewChangeListeners = [];
24963           this.$untouched = true;
24964           this.$touched = false;
24965           this.$pristine = true;
24966           this.$dirty = false;
24967           this.$valid = true;
24968           this.$invalid = false;
24969           this.$error = {}; // keep invalid keys here
24970           this.$$success = {}; // keep valid keys here
24971           this.$pending = undefined; // keep pending keys here
24972           this.$name = $interpolate($attr.name || '', false)($scope);
24973           this.$$parentForm = nullFormCtrl;
24974
24975           var parsedNgModel = $parse($attr.ngModel),
24976               parsedNgModelAssign = parsedNgModel.assign,
24977               ngModelGet = parsedNgModel,
24978               ngModelSet = parsedNgModelAssign,
24979               pendingDebounce = null,
24980               parserValid,
24981               ctrl = this;
24982
24983           this.$$setOptions = function(options) {
24984             ctrl.$options = options;
24985             if (options && options.getterSetter) {
24986               var invokeModelGetter = $parse($attr.ngModel + '()'),
24987                   invokeModelSetter = $parse($attr.ngModel + '($$$p)');
24988
24989               ngModelGet = function($scope) {
24990                 var modelValue = parsedNgModel($scope);
24991                 if (isFunction(modelValue)) {
24992                   modelValue = invokeModelGetter($scope);
24993                 }
24994                 return modelValue;
24995               };
24996               ngModelSet = function($scope, newValue) {
24997                 if (isFunction(parsedNgModel($scope))) {
24998                   invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
24999                 } else {
25000                   parsedNgModelAssign($scope, ctrl.$modelValue);
25001                 }
25002               };
25003             } else if (!parsedNgModel.assign) {
25004               throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
25005                   $attr.ngModel, startingTag($element));
25006             }
25007           };
25008
25009           /**
25010            * @ngdoc method
25011            * @name ngModel.NgModelController#$render
25012            *
25013            * @description
25014            * Called when the view needs to be updated. It is expected that the user of the ng-model
25015            * directive will implement this method.
25016            *
25017            * The `$render()` method is invoked in the following situations:
25018            *
25019            * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
25020            *   committed value then `$render()` is called to update the input control.
25021            * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
25022            *   the `$viewValue` are different from last time.
25023            *
25024            * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
25025            * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
25026            * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
25027            * invoked if you only change a property on the objects.
25028            */
25029           this.$render = noop;
25030
25031           /**
25032            * @ngdoc method
25033            * @name ngModel.NgModelController#$isEmpty
25034            *
25035            * @description
25036            * This is called when we need to determine if the value of an input is empty.
25037            *
25038            * For instance, the required directive does this to work out if the input has data or not.
25039            *
25040            * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
25041            *
25042            * You can override this for input directives whose concept of being empty is different from the
25043            * default. The `checkboxInputType` directive does this because in its case a value of `false`
25044            * implies empty.
25045            *
25046            * @param {*} value The value of the input to check for emptiness.
25047            * @returns {boolean} True if `value` is "empty".
25048            */
25049           this.$isEmpty = function(value) {
25050             return isUndefined(value) || value === '' || value === null || value !== value;
25051           };
25052
25053           var currentValidationRunId = 0;
25054
25055           /**
25056            * @ngdoc method
25057            * @name ngModel.NgModelController#$setValidity
25058            *
25059            * @description
25060            * Change the validity state, and notify the form.
25061            *
25062            * This method can be called within $parsers/$formatters or a custom validation implementation.
25063            * However, in most cases it should be sufficient to use the `ngModel.$validators` and
25064            * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
25065            *
25066            * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
25067            *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
25068            *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
25069            *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
25070            *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
25071            *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
25072            * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
25073            *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
25074            *                          Skipped is used by Angular when validators do not run because of parse errors and
25075            *                          when `$asyncValidators` do not run because any of the `$validators` failed.
25076            */
25077           addSetValidityMethod({
25078             ctrl: this,
25079             $element: $element,
25080             set: function(object, property) {
25081               object[property] = true;
25082             },
25083             unset: function(object, property) {
25084               delete object[property];
25085             },
25086             $animate: $animate
25087           });
25088
25089           /**
25090            * @ngdoc method
25091            * @name ngModel.NgModelController#$setPristine
25092            *
25093            * @description
25094            * Sets the control to its pristine state.
25095            *
25096            * This method can be called to remove the `ng-dirty` class and set the control to its pristine
25097            * state (`ng-pristine` class). A model is considered to be pristine when the control
25098            * has not been changed from when first compiled.
25099            */
25100           this.$setPristine = function() {
25101             ctrl.$dirty = false;
25102             ctrl.$pristine = true;
25103             $animate.removeClass($element, DIRTY_CLASS);
25104             $animate.addClass($element, PRISTINE_CLASS);
25105           };
25106
25107           /**
25108            * @ngdoc method
25109            * @name ngModel.NgModelController#$setDirty
25110            *
25111            * @description
25112            * Sets the control to its dirty state.
25113            *
25114            * This method can be called to remove the `ng-pristine` class and set the control to its dirty
25115            * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
25116            * from when first compiled.
25117            */
25118           this.$setDirty = function() {
25119             ctrl.$dirty = true;
25120             ctrl.$pristine = false;
25121             $animate.removeClass($element, PRISTINE_CLASS);
25122             $animate.addClass($element, DIRTY_CLASS);
25123             ctrl.$$parentForm.$setDirty();
25124           };
25125
25126           /**
25127            * @ngdoc method
25128            * @name ngModel.NgModelController#$setUntouched
25129            *
25130            * @description
25131            * Sets the control to its untouched state.
25132            *
25133            * This method can be called to remove the `ng-touched` class and set the control to its
25134            * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
25135            * by default, however this function can be used to restore that state if the model has
25136            * already been touched by the user.
25137            */
25138           this.$setUntouched = function() {
25139             ctrl.$touched = false;
25140             ctrl.$untouched = true;
25141             $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
25142           };
25143
25144           /**
25145            * @ngdoc method
25146            * @name ngModel.NgModelController#$setTouched
25147            *
25148            * @description
25149            * Sets the control to its touched state.
25150            *
25151            * This method can be called to remove the `ng-untouched` class and set the control to its
25152            * touched state (`ng-touched` class). A model is considered to be touched when the user has
25153            * first focused the control element and then shifted focus away from the control (blur event).
25154            */
25155           this.$setTouched = function() {
25156             ctrl.$touched = true;
25157             ctrl.$untouched = false;
25158             $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
25159           };
25160
25161           /**
25162            * @ngdoc method
25163            * @name ngModel.NgModelController#$rollbackViewValue
25164            *
25165            * @description
25166            * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
25167            * which may be caused by a pending debounced event or because the input is waiting for a some
25168            * future event.
25169            *
25170            * If you have an input that uses `ng-model-options` to set up debounced events or events such
25171            * as blur you can have a situation where there is a period when the `$viewValue`
25172            * is out of synch with the ngModel's `$modelValue`.
25173            *
25174            * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
25175            * programmatically before these debounced/future events have resolved/occurred, because Angular's
25176            * dirty checking mechanism is not able to tell whether the model has actually changed or not.
25177            *
25178            * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
25179            * input which may have such events pending. This is important in order to make sure that the
25180            * input field will be updated with the new model value and any pending operations are cancelled.
25181            *
25182            * <example name="ng-model-cancel-update" module="cancel-update-example">
25183            *   <file name="app.js">
25184            *     angular.module('cancel-update-example', [])
25185            *
25186            *     .controller('CancelUpdateController', ['$scope', function($scope) {
25187            *       $scope.resetWithCancel = function(e) {
25188            *         if (e.keyCode == 27) {
25189            *           $scope.myForm.myInput1.$rollbackViewValue();
25190            *           $scope.myValue = '';
25191            *         }
25192            *       };
25193            *       $scope.resetWithoutCancel = function(e) {
25194            *         if (e.keyCode == 27) {
25195            *           $scope.myValue = '';
25196            *         }
25197            *       };
25198            *     }]);
25199            *   </file>
25200            *   <file name="index.html">
25201            *     <div ng-controller="CancelUpdateController">
25202            *       <p>Try typing something in each input.  See that the model only updates when you
25203            *          blur off the input.
25204            *        </p>
25205            *        <p>Now see what happens if you start typing then press the Escape key</p>
25206            *
25207            *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
25208            *         <p id="inputDescription1">With $rollbackViewValue()</p>
25209            *         <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
25210            *                ng-keydown="resetWithCancel($event)"><br/>
25211            *         myValue: "{{ myValue }}"
25212            *
25213            *         <p id="inputDescription2">Without $rollbackViewValue()</p>
25214            *         <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
25215            *                ng-keydown="resetWithoutCancel($event)"><br/>
25216            *         myValue: "{{ myValue }}"
25217            *       </form>
25218            *     </div>
25219            *   </file>
25220            * </example>
25221            */
25222           this.$rollbackViewValue = function() {
25223             $timeout.cancel(pendingDebounce);
25224             ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
25225             ctrl.$render();
25226           };
25227
25228           /**
25229            * @ngdoc method
25230            * @name ngModel.NgModelController#$validate
25231            *
25232            * @description
25233            * Runs each of the registered validators (first synchronous validators and then
25234            * asynchronous validators).
25235            * If the validity changes to invalid, the model will be set to `undefined`,
25236            * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
25237            * If the validity changes to valid, it will set the model to the last available valid
25238            * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
25239            */
25240           this.$validate = function() {
25241             // ignore $validate before model is initialized
25242             if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
25243               return;
25244             }
25245
25246             var viewValue = ctrl.$$lastCommittedViewValue;
25247             // Note: we use the $$rawModelValue as $modelValue might have been
25248             // set to undefined during a view -> model update that found validation
25249             // errors. We can't parse the view here, since that could change
25250             // the model although neither viewValue nor the model on the scope changed
25251             var modelValue = ctrl.$$rawModelValue;
25252
25253             var prevValid = ctrl.$valid;
25254             var prevModelValue = ctrl.$modelValue;
25255
25256             var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
25257
25258             ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
25259               // If there was no change in validity, don't update the model
25260               // This prevents changing an invalid modelValue to undefined
25261               if (!allowInvalid && prevValid !== allValid) {
25262                 // Note: Don't check ctrl.$valid here, as we could have
25263                 // external validators (e.g. calculated on the server),
25264                 // that just call $setValidity and need the model value
25265                 // to calculate their validity.
25266                 ctrl.$modelValue = allValid ? modelValue : undefined;
25267
25268                 if (ctrl.$modelValue !== prevModelValue) {
25269                   ctrl.$$writeModelToScope();
25270                 }
25271               }
25272             });
25273
25274           };
25275
25276           this.$$runValidators = function(modelValue, viewValue, doneCallback) {
25277             currentValidationRunId++;
25278             var localValidationRunId = currentValidationRunId;
25279
25280             // check parser error
25281             if (!processParseErrors()) {
25282               validationDone(false);
25283               return;
25284             }
25285             if (!processSyncValidators()) {
25286               validationDone(false);
25287               return;
25288             }
25289             processAsyncValidators();
25290
25291             function processParseErrors() {
25292               var errorKey = ctrl.$$parserName || 'parse';
25293               if (isUndefined(parserValid)) {
25294                 setValidity(errorKey, null);
25295               } else {
25296                 if (!parserValid) {
25297                   forEach(ctrl.$validators, function(v, name) {
25298                     setValidity(name, null);
25299                   });
25300                   forEach(ctrl.$asyncValidators, function(v, name) {
25301                     setValidity(name, null);
25302                   });
25303                 }
25304                 // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
25305                 setValidity(errorKey, parserValid);
25306                 return parserValid;
25307               }
25308               return true;
25309             }
25310
25311             function processSyncValidators() {
25312               var syncValidatorsValid = true;
25313               forEach(ctrl.$validators, function(validator, name) {
25314                 var result = validator(modelValue, viewValue);
25315                 syncValidatorsValid = syncValidatorsValid && result;
25316                 setValidity(name, result);
25317               });
25318               if (!syncValidatorsValid) {
25319                 forEach(ctrl.$asyncValidators, function(v, name) {
25320                   setValidity(name, null);
25321                 });
25322                 return false;
25323               }
25324               return true;
25325             }
25326
25327             function processAsyncValidators() {
25328               var validatorPromises = [];
25329               var allValid = true;
25330               forEach(ctrl.$asyncValidators, function(validator, name) {
25331                 var promise = validator(modelValue, viewValue);
25332                 if (!isPromiseLike(promise)) {
25333                   throw ngModelMinErr("$asyncValidators",
25334                     "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
25335                 }
25336                 setValidity(name, undefined);
25337                 validatorPromises.push(promise.then(function() {
25338                   setValidity(name, true);
25339                 }, function(error) {
25340                   allValid = false;
25341                   setValidity(name, false);
25342                 }));
25343               });
25344               if (!validatorPromises.length) {
25345                 validationDone(true);
25346               } else {
25347                 $q.all(validatorPromises).then(function() {
25348                   validationDone(allValid);
25349                 }, noop);
25350               }
25351             }
25352
25353             function setValidity(name, isValid) {
25354               if (localValidationRunId === currentValidationRunId) {
25355                 ctrl.$setValidity(name, isValid);
25356               }
25357             }
25358
25359             function validationDone(allValid) {
25360               if (localValidationRunId === currentValidationRunId) {
25361
25362                 doneCallback(allValid);
25363               }
25364             }
25365           };
25366
25367           /**
25368            * @ngdoc method
25369            * @name ngModel.NgModelController#$commitViewValue
25370            *
25371            * @description
25372            * Commit a pending update to the `$modelValue`.
25373            *
25374            * Updates may be pending by a debounced event or because the input is waiting for a some future
25375            * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
25376            * usually handles calling this in response to input events.
25377            */
25378           this.$commitViewValue = function() {
25379             var viewValue = ctrl.$viewValue;
25380
25381             $timeout.cancel(pendingDebounce);
25382
25383             // If the view value has not changed then we should just exit, except in the case where there is
25384             // a native validator on the element. In this case the validation state may have changed even though
25385             // the viewValue has stayed empty.
25386             if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
25387               return;
25388             }
25389             ctrl.$$lastCommittedViewValue = viewValue;
25390
25391             // change to dirty
25392             if (ctrl.$pristine) {
25393               this.$setDirty();
25394             }
25395             this.$$parseAndValidate();
25396           };
25397
25398           this.$$parseAndValidate = function() {
25399             var viewValue = ctrl.$$lastCommittedViewValue;
25400             var modelValue = viewValue;
25401             parserValid = isUndefined(modelValue) ? undefined : true;
25402
25403             if (parserValid) {
25404               for (var i = 0; i < ctrl.$parsers.length; i++) {
25405                 modelValue = ctrl.$parsers[i](modelValue);
25406                 if (isUndefined(modelValue)) {
25407                   parserValid = false;
25408                   break;
25409                 }
25410               }
25411             }
25412             if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
25413               // ctrl.$modelValue has not been touched yet...
25414               ctrl.$modelValue = ngModelGet($scope);
25415             }
25416             var prevModelValue = ctrl.$modelValue;
25417             var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
25418             ctrl.$$rawModelValue = modelValue;
25419
25420             if (allowInvalid) {
25421               ctrl.$modelValue = modelValue;
25422               writeToModelIfNeeded();
25423             }
25424
25425             // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
25426             // This can happen if e.g. $setViewValue is called from inside a parser
25427             ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
25428               if (!allowInvalid) {
25429                 // Note: Don't check ctrl.$valid here, as we could have
25430                 // external validators (e.g. calculated on the server),
25431                 // that just call $setValidity and need the model value
25432                 // to calculate their validity.
25433                 ctrl.$modelValue = allValid ? modelValue : undefined;
25434                 writeToModelIfNeeded();
25435               }
25436             });
25437
25438             function writeToModelIfNeeded() {
25439               if (ctrl.$modelValue !== prevModelValue) {
25440                 ctrl.$$writeModelToScope();
25441               }
25442             }
25443           };
25444
25445           this.$$writeModelToScope = function() {
25446             ngModelSet($scope, ctrl.$modelValue);
25447             forEach(ctrl.$viewChangeListeners, function(listener) {
25448               try {
25449                 listener();
25450               } catch (e) {
25451                 $exceptionHandler(e);
25452               }
25453             });
25454           };
25455
25456           /**
25457            * @ngdoc method
25458            * @name ngModel.NgModelController#$setViewValue
25459            *
25460            * @description
25461            * Update the view value.
25462            *
25463            * This method should be called when a control wants to change the view value; typically,
25464            * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
25465            * directive calls it when the value of the input changes and {@link ng.directive:select select}
25466            * calls it when an option is selected.
25467            *
25468            * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
25469            * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
25470            * value sent directly for processing, finally to be applied to `$modelValue` and then the
25471            * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
25472            * in the `$viewChangeListeners` list, are called.
25473            *
25474            * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
25475            * and the `default` trigger is not listed, all those actions will remain pending until one of the
25476            * `updateOn` events is triggered on the DOM element.
25477            * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
25478            * directive is used with a custom debounce for this particular event.
25479            * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
25480            * is specified, once the timer runs out.
25481            *
25482            * When used with standard inputs, the view value will always be a string (which is in some cases
25483            * parsed into another type, such as a `Date` object for `input[date]`.)
25484            * However, custom controls might also pass objects to this method. In this case, we should make
25485            * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
25486            * perform a deep watch of objects, it only looks for a change of identity. If you only change
25487            * the property of the object then ngModel will not realise that the object has changed and
25488            * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
25489            * not change properties of the copy once it has been passed to `$setViewValue`.
25490            * Otherwise you may cause the model value on the scope to change incorrectly.
25491            *
25492            * <div class="alert alert-info">
25493            * In any case, the value passed to the method should always reflect the current value
25494            * of the control. For example, if you are calling `$setViewValue` for an input element,
25495            * you should pass the input DOM value. Otherwise, the control and the scope model become
25496            * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
25497            * the control's DOM value in any way. If we want to change the control's DOM value
25498            * programmatically, we should update the `ngModel` scope expression. Its new value will be
25499            * picked up by the model controller, which will run it through the `$formatters`, `$render` it
25500            * to update the DOM, and finally call `$validate` on it.
25501            * </div>
25502            *
25503            * @param {*} value value from the view.
25504            * @param {string} trigger Event that triggered the update.
25505            */
25506           this.$setViewValue = function(value, trigger) {
25507             ctrl.$viewValue = value;
25508             if (!ctrl.$options || ctrl.$options.updateOnDefault) {
25509               ctrl.$$debounceViewValueCommit(trigger);
25510             }
25511           };
25512
25513           this.$$debounceViewValueCommit = function(trigger) {
25514             var debounceDelay = 0,
25515                 options = ctrl.$options,
25516                 debounce;
25517
25518             if (options && isDefined(options.debounce)) {
25519               debounce = options.debounce;
25520               if (isNumber(debounce)) {
25521                 debounceDelay = debounce;
25522               } else if (isNumber(debounce[trigger])) {
25523                 debounceDelay = debounce[trigger];
25524               } else if (isNumber(debounce['default'])) {
25525                 debounceDelay = debounce['default'];
25526               }
25527             }
25528
25529             $timeout.cancel(pendingDebounce);
25530             if (debounceDelay) {
25531               pendingDebounce = $timeout(function() {
25532                 ctrl.$commitViewValue();
25533               }, debounceDelay);
25534             } else if ($rootScope.$$phase) {
25535               ctrl.$commitViewValue();
25536             } else {
25537               $scope.$apply(function() {
25538                 ctrl.$commitViewValue();
25539               });
25540             }
25541           };
25542
25543           // model -> value
25544           // Note: we cannot use a normal scope.$watch as we want to detect the following:
25545           // 1. scope value is 'a'
25546           // 2. user enters 'b'
25547           // 3. ng-change kicks in and reverts scope value to 'a'
25548           //    -> scope value did not change since the last digest as
25549           //       ng-change executes in apply phase
25550           // 4. view should be changed back to 'a'
25551           $scope.$watch(function ngModelWatch() {
25552             var modelValue = ngModelGet($scope);
25553
25554             // if scope model value and ngModel value are out of sync
25555             // TODO(perf): why not move this to the action fn?
25556             if (modelValue !== ctrl.$modelValue &&
25557                // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
25558                (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
25559             ) {
25560               ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
25561               parserValid = undefined;
25562
25563               var formatters = ctrl.$formatters,
25564                   idx = formatters.length;
25565
25566               var viewValue = modelValue;
25567               while (idx--) {
25568                 viewValue = formatters[idx](viewValue);
25569               }
25570               if (ctrl.$viewValue !== viewValue) {
25571                 ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
25572                 ctrl.$render();
25573
25574                 ctrl.$$runValidators(modelValue, viewValue, noop);
25575               }
25576             }
25577
25578             return modelValue;
25579           });
25580         }];
25581
25582
25583         /**
25584          * @ngdoc directive
25585          * @name ngModel
25586          *
25587          * @element input
25588          * @priority 1
25589          *
25590          * @description
25591          * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
25592          * property on the scope using {@link ngModel.NgModelController NgModelController},
25593          * which is created and exposed by this directive.
25594          *
25595          * `ngModel` is responsible for:
25596          *
25597          * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
25598          *   require.
25599          * - Providing validation behavior (i.e. required, number, email, url).
25600          * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
25601          * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
25602          * - Registering the control with its parent {@link ng.directive:form form}.
25603          *
25604          * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
25605          * current scope. If the property doesn't already exist on this scope, it will be created
25606          * implicitly and added to the scope.
25607          *
25608          * For best practices on using `ngModel`, see:
25609          *
25610          *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
25611          *
25612          * For basic examples, how to use `ngModel`, see:
25613          *
25614          *  - {@link ng.directive:input input}
25615          *    - {@link input[text] text}
25616          *    - {@link input[checkbox] checkbox}
25617          *    - {@link input[radio] radio}
25618          *    - {@link input[number] number}
25619          *    - {@link input[email] email}
25620          *    - {@link input[url] url}
25621          *    - {@link input[date] date}
25622          *    - {@link input[datetime-local] datetime-local}
25623          *    - {@link input[time] time}
25624          *    - {@link input[month] month}
25625          *    - {@link input[week] week}
25626          *  - {@link ng.directive:select select}
25627          *  - {@link ng.directive:textarea textarea}
25628          *
25629          * # CSS classes
25630          * The following CSS classes are added and removed on the associated input/select/textarea element
25631          * depending on the validity of the model.
25632          *
25633          *  - `ng-valid`: the model is valid
25634          *  - `ng-invalid`: the model is invalid
25635          *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
25636          *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
25637          *  - `ng-pristine`: the control hasn't been interacted with yet
25638          *  - `ng-dirty`: the control has been interacted with
25639          *  - `ng-touched`: the control has been blurred
25640          *  - `ng-untouched`: the control hasn't been blurred
25641          *  - `ng-pending`: any `$asyncValidators` are unfulfilled
25642          *
25643          * Keep in mind that ngAnimate can detect each of these classes when added and removed.
25644          *
25645          * ## Animation Hooks
25646          *
25647          * Animations within models are triggered when any of the associated CSS classes are added and removed
25648          * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
25649          * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
25650          * The animations that are triggered within ngModel are similar to how they work in ngClass and
25651          * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
25652          *
25653          * The following example shows a simple way to utilize CSS transitions to style an input element
25654          * that has been rendered as invalid after it has been validated:
25655          *
25656          * <pre>
25657          * //be sure to include ngAnimate as a module to hook into more
25658          * //advanced animations
25659          * .my-input {
25660          *   transition:0.5s linear all;
25661          *   background: white;
25662          * }
25663          * .my-input.ng-invalid {
25664          *   background: red;
25665          *   color:white;
25666          * }
25667          * </pre>
25668          *
25669          * @example
25670          * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
25671              <file name="index.html">
25672                <script>
25673                 angular.module('inputExample', [])
25674                   .controller('ExampleController', ['$scope', function($scope) {
25675                     $scope.val = '1';
25676                   }]);
25677                </script>
25678                <style>
25679                  .my-input {
25680                    transition:all linear 0.5s;
25681                    background: transparent;
25682                  }
25683                  .my-input.ng-invalid {
25684                    color:white;
25685                    background: red;
25686                  }
25687                </style>
25688                <p id="inputDescription">
25689                 Update input to see transitions when valid/invalid.
25690                 Integer is a valid value.
25691                </p>
25692                <form name="testForm" ng-controller="ExampleController">
25693                  <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
25694                         aria-describedby="inputDescription" />
25695                </form>
25696              </file>
25697          * </example>
25698          *
25699          * ## Binding to a getter/setter
25700          *
25701          * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
25702          * function that returns a representation of the model when called with zero arguments, and sets
25703          * the internal state of a model when called with an argument. It's sometimes useful to use this
25704          * for models that have an internal representation that's different from what the model exposes
25705          * to the view.
25706          *
25707          * <div class="alert alert-success">
25708          * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
25709          * frequently than other parts of your code.
25710          * </div>
25711          *
25712          * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
25713          * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
25714          * a `<form>`, which will enable this behavior for all `<input>`s within it. See
25715          * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
25716          *
25717          * The following example shows how to use `ngModel` with a getter/setter:
25718          *
25719          * @example
25720          * <example name="ngModel-getter-setter" module="getterSetterExample">
25721              <file name="index.html">
25722                <div ng-controller="ExampleController">
25723                  <form name="userForm">
25724                    <label>Name:
25725                      <input type="text" name="userName"
25726                             ng-model="user.name"
25727                             ng-model-options="{ getterSetter: true }" />
25728                    </label>
25729                  </form>
25730                  <pre>user.name = <span ng-bind="user.name()"></span></pre>
25731                </div>
25732              </file>
25733              <file name="app.js">
25734                angular.module('getterSetterExample', [])
25735                  .controller('ExampleController', ['$scope', function($scope) {
25736                    var _name = 'Brian';
25737                    $scope.user = {
25738                      name: function(newName) {
25739                       // Note that newName can be undefined for two reasons:
25740                       // 1. Because it is called as a getter and thus called with no arguments
25741                       // 2. Because the property should actually be set to undefined. This happens e.g. if the
25742                       //    input is invalid
25743                       return arguments.length ? (_name = newName) : _name;
25744                      }
25745                    };
25746                  }]);
25747              </file>
25748          * </example>
25749          */
25750         var ngModelDirective = ['$rootScope', function($rootScope) {
25751           return {
25752             restrict: 'A',
25753             require: ['ngModel', '^?form', '^?ngModelOptions'],
25754             controller: NgModelController,
25755             // Prelink needs to run before any input directive
25756             // so that we can set the NgModelOptions in NgModelController
25757             // before anyone else uses it.
25758             priority: 1,
25759             compile: function ngModelCompile(element) {
25760               // Setup initial state of the control
25761               element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
25762
25763               return {
25764                 pre: function ngModelPreLink(scope, element, attr, ctrls) {
25765                   var modelCtrl = ctrls[0],
25766                       formCtrl = ctrls[1] || modelCtrl.$$parentForm;
25767
25768                   modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
25769
25770                   // notify others, especially parent forms
25771                   formCtrl.$addControl(modelCtrl);
25772
25773                   attr.$observe('name', function(newValue) {
25774                     if (modelCtrl.$name !== newValue) {
25775                       modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
25776                     }
25777                   });
25778
25779                   scope.$on('$destroy', function() {
25780                     modelCtrl.$$parentForm.$removeControl(modelCtrl);
25781                   });
25782                 },
25783                 post: function ngModelPostLink(scope, element, attr, ctrls) {
25784                   var modelCtrl = ctrls[0];
25785                   if (modelCtrl.$options && modelCtrl.$options.updateOn) {
25786                     element.on(modelCtrl.$options.updateOn, function(ev) {
25787                       modelCtrl.$$debounceViewValueCommit(ev && ev.type);
25788                     });
25789                   }
25790
25791                   element.on('blur', function(ev) {
25792                     if (modelCtrl.$touched) return;
25793
25794                     if ($rootScope.$$phase) {
25795                       scope.$evalAsync(modelCtrl.$setTouched);
25796                     } else {
25797                       scope.$apply(modelCtrl.$setTouched);
25798                     }
25799                   });
25800                 }
25801               };
25802             }
25803           };
25804         }];
25805
25806         var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
25807
25808         /**
25809          * @ngdoc directive
25810          * @name ngModelOptions
25811          *
25812          * @description
25813          * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
25814          * events that will trigger a model update and/or a debouncing delay so that the actual update only
25815          * takes place when a timer expires; this timer will be reset after another change takes place.
25816          *
25817          * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
25818          * be different from the value in the actual model. This means that if you update the model you
25819          * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
25820          * order to make sure it is synchronized with the model and that any debounced action is canceled.
25821          *
25822          * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
25823          * method is by making sure the input is placed inside a form that has a `name` attribute. This is
25824          * important because `form` controllers are published to the related scope under the name in their
25825          * `name` attribute.
25826          *
25827          * Any pending changes will take place immediately when an enclosing form is submitted via the
25828          * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
25829          * to have access to the updated model.
25830          *
25831          * `ngModelOptions` has an effect on the element it's declared on and its descendants.
25832          *
25833          * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
25834          *   - `updateOn`: string specifying which event should the input be bound to. You can set several
25835          *     events using an space delimited list. There is a special event called `default` that
25836          *     matches the default events belonging of the control.
25837          *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
25838          *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
25839          *     custom value for each event. For example:
25840          *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
25841          *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
25842          *     not validate correctly instead of the default behavior of setting the model to undefined.
25843          *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
25844                `ngModel` as getters/setters.
25845          *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
25846          *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
25847          *     continental US time zone abbreviations, but for general use, use a time zone offset, for
25848          *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
25849          *     If not specified, the timezone of the browser will be used.
25850          *
25851          * @example
25852
25853           The following example shows how to override immediate updates. Changes on the inputs within the
25854           form will update the model only when the control loses focus (blur event). If `escape` key is
25855           pressed while the input field is focused, the value is reset to the value in the current model.
25856
25857           <example name="ngModelOptions-directive-blur" module="optionsExample">
25858             <file name="index.html">
25859               <div ng-controller="ExampleController">
25860                 <form name="userForm">
25861                   <label>Name:
25862                     <input type="text" name="userName"
25863                            ng-model="user.name"
25864                            ng-model-options="{ updateOn: 'blur' }"
25865                            ng-keyup="cancel($event)" />
25866                   </label><br />
25867                   <label>Other data:
25868                     <input type="text" ng-model="user.data" />
25869                   </label><br />
25870                 </form>
25871                 <pre>user.name = <span ng-bind="user.name"></span></pre>
25872                 <pre>user.data = <span ng-bind="user.data"></span></pre>
25873               </div>
25874             </file>
25875             <file name="app.js">
25876               angular.module('optionsExample', [])
25877                 .controller('ExampleController', ['$scope', function($scope) {
25878                   $scope.user = { name: 'John', data: '' };
25879
25880                   $scope.cancel = function(e) {
25881                     if (e.keyCode == 27) {
25882                       $scope.userForm.userName.$rollbackViewValue();
25883                     }
25884                   };
25885                 }]);
25886             </file>
25887             <file name="protractor.js" type="protractor">
25888               var model = element(by.binding('user.name'));
25889               var input = element(by.model('user.name'));
25890               var other = element(by.model('user.data'));
25891
25892               it('should allow custom events', function() {
25893                 input.sendKeys(' Doe');
25894                 input.click();
25895                 expect(model.getText()).toEqual('John');
25896                 other.click();
25897                 expect(model.getText()).toEqual('John Doe');
25898               });
25899
25900               it('should $rollbackViewValue when model changes', function() {
25901                 input.sendKeys(' Doe');
25902                 expect(input.getAttribute('value')).toEqual('John Doe');
25903                 input.sendKeys(protractor.Key.ESCAPE);
25904                 expect(input.getAttribute('value')).toEqual('John');
25905                 other.click();
25906                 expect(model.getText()).toEqual('John');
25907               });
25908             </file>
25909           </example>
25910
25911           This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
25912           If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
25913
25914           <example name="ngModelOptions-directive-debounce" module="optionsExample">
25915             <file name="index.html">
25916               <div ng-controller="ExampleController">
25917                 <form name="userForm">
25918                   <label>Name:
25919                     <input type="text" name="userName"
25920                            ng-model="user.name"
25921                            ng-model-options="{ debounce: 1000 }" />
25922                   </label>
25923                   <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
25924                   <br />
25925                 </form>
25926                 <pre>user.name = <span ng-bind="user.name"></span></pre>
25927               </div>
25928             </file>
25929             <file name="app.js">
25930               angular.module('optionsExample', [])
25931                 .controller('ExampleController', ['$scope', function($scope) {
25932                   $scope.user = { name: 'Igor' };
25933                 }]);
25934             </file>
25935           </example>
25936
25937           This one shows how to bind to getter/setters:
25938
25939           <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
25940             <file name="index.html">
25941               <div ng-controller="ExampleController">
25942                 <form name="userForm">
25943                   <label>Name:
25944                     <input type="text" name="userName"
25945                            ng-model="user.name"
25946                            ng-model-options="{ getterSetter: true }" />
25947                   </label>
25948                 </form>
25949                 <pre>user.name = <span ng-bind="user.name()"></span></pre>
25950               </div>
25951             </file>
25952             <file name="app.js">
25953               angular.module('getterSetterExample', [])
25954                 .controller('ExampleController', ['$scope', function($scope) {
25955                   var _name = 'Brian';
25956                   $scope.user = {
25957                     name: function(newName) {
25958                       // Note that newName can be undefined for two reasons:
25959                       // 1. Because it is called as a getter and thus called with no arguments
25960                       // 2. Because the property should actually be set to undefined. This happens e.g. if the
25961                       //    input is invalid
25962                       return arguments.length ? (_name = newName) : _name;
25963                     }
25964                   };
25965                 }]);
25966             </file>
25967           </example>
25968          */
25969         var ngModelOptionsDirective = function() {
25970           return {
25971             restrict: 'A',
25972             controller: ['$scope', '$attrs', function($scope, $attrs) {
25973               var that = this;
25974               this.$options = copy($scope.$eval($attrs.ngModelOptions));
25975               // Allow adding/overriding bound events
25976               if (isDefined(this.$options.updateOn)) {
25977                 this.$options.updateOnDefault = false;
25978                 // extract "default" pseudo-event from list of events that can trigger a model update
25979                 this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
25980                   that.$options.updateOnDefault = true;
25981                   return ' ';
25982                 }));
25983               } else {
25984                 this.$options.updateOnDefault = true;
25985               }
25986             }]
25987           };
25988         };
25989
25990
25991
25992         // helper methods
25993         function addSetValidityMethod(context) {
25994           var ctrl = context.ctrl,
25995               $element = context.$element,
25996               classCache = {},
25997               set = context.set,
25998               unset = context.unset,
25999               $animate = context.$animate;
26000
26001           classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
26002
26003           ctrl.$setValidity = setValidity;
26004
26005           function setValidity(validationErrorKey, state, controller) {
26006             if (isUndefined(state)) {
26007               createAndSet('$pending', validationErrorKey, controller);
26008             } else {
26009               unsetAndCleanup('$pending', validationErrorKey, controller);
26010             }
26011             if (!isBoolean(state)) {
26012               unset(ctrl.$error, validationErrorKey, controller);
26013               unset(ctrl.$$success, validationErrorKey, controller);
26014             } else {
26015               if (state) {
26016                 unset(ctrl.$error, validationErrorKey, controller);
26017                 set(ctrl.$$success, validationErrorKey, controller);
26018               } else {
26019                 set(ctrl.$error, validationErrorKey, controller);
26020                 unset(ctrl.$$success, validationErrorKey, controller);
26021               }
26022             }
26023             if (ctrl.$pending) {
26024               cachedToggleClass(PENDING_CLASS, true);
26025               ctrl.$valid = ctrl.$invalid = undefined;
26026               toggleValidationCss('', null);
26027             } else {
26028               cachedToggleClass(PENDING_CLASS, false);
26029               ctrl.$valid = isObjectEmpty(ctrl.$error);
26030               ctrl.$invalid = !ctrl.$valid;
26031               toggleValidationCss('', ctrl.$valid);
26032             }
26033
26034             // re-read the state as the set/unset methods could have
26035             // combined state in ctrl.$error[validationError] (used for forms),
26036             // where setting/unsetting only increments/decrements the value,
26037             // and does not replace it.
26038             var combinedState;
26039             if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
26040               combinedState = undefined;
26041             } else if (ctrl.$error[validationErrorKey]) {
26042               combinedState = false;
26043             } else if (ctrl.$$success[validationErrorKey]) {
26044               combinedState = true;
26045             } else {
26046               combinedState = null;
26047             }
26048
26049             toggleValidationCss(validationErrorKey, combinedState);
26050             ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
26051           }
26052
26053           function createAndSet(name, value, controller) {
26054             if (!ctrl[name]) {
26055               ctrl[name] = {};
26056             }
26057             set(ctrl[name], value, controller);
26058           }
26059
26060           function unsetAndCleanup(name, value, controller) {
26061             if (ctrl[name]) {
26062               unset(ctrl[name], value, controller);
26063             }
26064             if (isObjectEmpty(ctrl[name])) {
26065               ctrl[name] = undefined;
26066             }
26067           }
26068
26069           function cachedToggleClass(className, switchValue) {
26070             if (switchValue && !classCache[className]) {
26071               $animate.addClass($element, className);
26072               classCache[className] = true;
26073             } else if (!switchValue && classCache[className]) {
26074               $animate.removeClass($element, className);
26075               classCache[className] = false;
26076             }
26077           }
26078
26079           function toggleValidationCss(validationErrorKey, isValid) {
26080             validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
26081
26082             cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
26083             cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
26084           }
26085         }
26086
26087         function isObjectEmpty(obj) {
26088           if (obj) {
26089             for (var prop in obj) {
26090               if (obj.hasOwnProperty(prop)) {
26091                 return false;
26092               }
26093             }
26094           }
26095           return true;
26096         }
26097
26098         /**
26099          * @ngdoc directive
26100          * @name ngNonBindable
26101          * @restrict AC
26102          * @priority 1000
26103          *
26104          * @description
26105          * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
26106          * DOM element. This is useful if the element contains what appears to be Angular directives and
26107          * bindings but which should be ignored by Angular. This could be the case if you have a site that
26108          * displays snippets of code, for instance.
26109          *
26110          * @element ANY
26111          *
26112          * @example
26113          * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
26114          * but the one wrapped in `ngNonBindable` is left alone.
26115          *
26116          * @example
26117             <example>
26118               <file name="index.html">
26119                 <div>Normal: {{1 + 2}}</div>
26120                 <div ng-non-bindable>Ignored: {{1 + 2}}</div>
26121               </file>
26122               <file name="protractor.js" type="protractor">
26123                it('should check ng-non-bindable', function() {
26124                  expect(element(by.binding('1 + 2')).getText()).toContain('3');
26125                  expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
26126                });
26127               </file>
26128             </example>
26129          */
26130         var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
26131
26132         /* global jqLiteRemove */
26133
26134         var ngOptionsMinErr = minErr('ngOptions');
26135
26136         /**
26137          * @ngdoc directive
26138          * @name ngOptions
26139          * @restrict A
26140          *
26141          * @description
26142          *
26143          * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
26144          * elements for the `<select>` element using the array or object obtained by evaluating the
26145          * `ngOptions` comprehension expression.
26146          *
26147          * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
26148          * similar result. However, `ngOptions` provides some benefits such as reducing memory and
26149          * increasing speed by not creating a new scope for each repeated instance, as well as providing
26150          * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
26151          * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
26152          *  to a non-string value. This is because an option element can only be bound to string values at
26153          * present.
26154          *
26155          * When an item in the `<select>` menu is selected, the array element or object property
26156          * represented by the selected option will be bound to the model identified by the `ngModel`
26157          * directive.
26158          *
26159          * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
26160          * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
26161          * option. See example below for demonstration.
26162          *
26163          * ## Complex Models (objects or collections)
26164          *
26165          * By default, `ngModel` watches the model by reference, not value. This is important to know when
26166          * binding the select to a model that is an object or a collection.
26167          *
26168          * One issue occurs if you want to preselect an option. For example, if you set
26169          * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
26170          * because the objects are not identical. So by default, you should always reference the item in your collection
26171          * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
26172          *
26173          * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
26174          * of the item not by reference, but by the result of the `track by` expression. For example, if your
26175          * collection items have an id property, you would `track by item.id`.
26176          *
26177          * A different issue with objects or collections is that ngModel won't detect if an object property or
26178          * a collection item changes. For that reason, `ngOptions` additionally watches the model using
26179          * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
26180          * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
26181          * has not changed identity, but only a property on the object or an item in the collection changes.
26182          *
26183          * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
26184          * if the model is an array). This means that changing a property deeper than the first level inside the
26185          * object/collection will not trigger a re-rendering.
26186          *
26187          * ## `select` **`as`**
26188          *
26189          * Using `select` **`as`** will bind the result of the `select` expression to the model, but
26190          * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
26191          * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
26192          * is used, the result of that expression will be set as the value of the `option` and `select` elements.
26193          *
26194          *
26195          * ### `select` **`as`** and **`track by`**
26196          *
26197          * <div class="alert alert-warning">
26198          * Be careful when using `select` **`as`** and **`track by`** in the same expression.
26199          * </div>
26200          *
26201          * Given this array of items on the $scope:
26202          *
26203          * ```js
26204          * $scope.items = [{
26205          *   id: 1,
26206          *   label: 'aLabel',
26207          *   subItem: { name: 'aSubItem' }
26208          * }, {
26209          *   id: 2,
26210          *   label: 'bLabel',
26211          *   subItem: { name: 'bSubItem' }
26212          * }];
26213          * ```
26214          *
26215          * This will work:
26216          *
26217          * ```html
26218          * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
26219          * ```
26220          * ```js
26221          * $scope.selected = $scope.items[0];
26222          * ```
26223          *
26224          * but this will not work:
26225          *
26226          * ```html
26227          * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
26228          * ```
26229          * ```js
26230          * $scope.selected = $scope.items[0].subItem;
26231          * ```
26232          *
26233          * In both examples, the **`track by`** expression is applied successfully to each `item` in the
26234          * `items` array. Because the selected option has been set programmatically in the controller, the
26235          * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
26236          * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
26237          * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
26238          * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
26239          * is not matched against any `<option>` and the `<select>` appears as having no selected value.
26240          *
26241          *
26242          * @param {string} ngModel Assignable angular expression to data-bind to.
26243          * @param {string=} name Property name of the form under which the control is published.
26244          * @param {string=} required The control is considered valid only if value is entered.
26245          * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26246          *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26247          *    `required` when you want to data-bind to the `required` attribute.
26248          * @param {comprehension_expression=} ngOptions in one of the following forms:
26249          *
26250          *   * for array data sources:
26251          *     * `label` **`for`** `value` **`in`** `array`
26252          *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
26253          *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
26254          *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
26255          *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26256          *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26257          *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
26258          *        (for including a filter with `track by`)
26259          *   * for object data sources:
26260          *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26261          *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26262          *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
26263          *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
26264          *     * `select` **`as`** `label` **`group by`** `group`
26265          *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26266          *     * `select` **`as`** `label` **`disable when`** `disable`
26267          *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26268          *
26269          * Where:
26270          *
26271          *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
26272          *   * `value`: local variable which will refer to each item in the `array` or each property value
26273          *      of `object` during iteration.
26274          *   * `key`: local variable which will refer to a property name in `object` during iteration.
26275          *   * `label`: The result of this expression will be the label for `<option>` element. The
26276          *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
26277          *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
26278          *      element. If not specified, `select` expression will default to `value`.
26279          *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
26280          *      DOM element.
26281          *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
26282          *      element. Return `true` to disable.
26283          *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
26284          *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
26285          *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
26286          *      even when the options are recreated (e.g. reloaded from the server).
26287          *
26288          * @example
26289             <example module="selectExample">
26290               <file name="index.html">
26291                 <script>
26292                 angular.module('selectExample', [])
26293                   .controller('ExampleController', ['$scope', function($scope) {
26294                     $scope.colors = [
26295                       {name:'black', shade:'dark'},
26296                       {name:'white', shade:'light', notAnOption: true},
26297                       {name:'red', shade:'dark'},
26298                       {name:'blue', shade:'dark', notAnOption: true},
26299                       {name:'yellow', shade:'light', notAnOption: false}
26300                     ];
26301                     $scope.myColor = $scope.colors[2]; // red
26302                   }]);
26303                 </script>
26304                 <div ng-controller="ExampleController">
26305                   <ul>
26306                     <li ng-repeat="color in colors">
26307                       <label>Name: <input ng-model="color.name"></label>
26308                       <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
26309                       <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
26310                     </li>
26311                     <li>
26312                       <button ng-click="colors.push({})">add</button>
26313                     </li>
26314                   </ul>
26315                   <hr/>
26316                   <label>Color (null not allowed):
26317                     <select ng-model="myColor" ng-options="color.name for color in colors"></select>
26318                   </label><br/>
26319                   <label>Color (null allowed):
26320                   <span  class="nullable">
26321                     <select ng-model="myColor" ng-options="color.name for color in colors">
26322                       <option value="">-- choose color --</option>
26323                     </select>
26324                   </span></label><br/>
26325
26326                   <label>Color grouped by shade:
26327                     <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
26328                     </select>
26329                   </label><br/>
26330
26331                   <label>Color grouped by shade, with some disabled:
26332                     <select ng-model="myColor"
26333                           ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
26334                     </select>
26335                   </label><br/>
26336
26337
26338
26339                   Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
26340                   <br/>
26341                   <hr/>
26342                   Currently selected: {{ {selected_color:myColor} }}
26343                   <div style="border:solid 1px black; height:20px"
26344                        ng-style="{'background-color':myColor.name}">
26345                   </div>
26346                 </div>
26347               </file>
26348               <file name="protractor.js" type="protractor">
26349                  it('should check ng-options', function() {
26350                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
26351                    element.all(by.model('myColor')).first().click();
26352                    element.all(by.css('select[ng-model="myColor"] option')).first().click();
26353                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
26354                    element(by.css('.nullable select[ng-model="myColor"]')).click();
26355                    element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
26356                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
26357                  });
26358               </file>
26359             </example>
26360          */
26361
26362         // jshint maxlen: false
26363         //                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
26364         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]+?))?$/;
26365                                 // 1: value expression (valueFn)
26366                                 // 2: label expression (displayFn)
26367                                 // 3: group by expression (groupByFn)
26368                                 // 4: disable when expression (disableWhenFn)
26369                                 // 5: array item variable name
26370                                 // 6: object item key variable name
26371                                 // 7: object item value variable name
26372                                 // 8: collection expression
26373                                 // 9: track by expression
26374         // jshint maxlen: 100
26375
26376
26377         var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26378
26379           function parseOptionsExpression(optionsExp, selectElement, scope) {
26380
26381             var match = optionsExp.match(NG_OPTIONS_REGEXP);
26382             if (!(match)) {
26383               throw ngOptionsMinErr('iexp',
26384                 "Expected expression in form of " +
26385                 "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
26386                 " but got '{0}'. Element: {1}",
26387                 optionsExp, startingTag(selectElement));
26388             }
26389
26390             // Extract the parts from the ngOptions expression
26391
26392             // The variable name for the value of the item in the collection
26393             var valueName = match[5] || match[7];
26394             // The variable name for the key of the item in the collection
26395             var keyName = match[6];
26396
26397             // An expression that generates the viewValue for an option if there is a label expression
26398             var selectAs = / as /.test(match[0]) && match[1];
26399             // An expression that is used to track the id of each object in the options collection
26400             var trackBy = match[9];
26401             // An expression that generates the viewValue for an option if there is no label expression
26402             var valueFn = $parse(match[2] ? match[1] : valueName);
26403             var selectAsFn = selectAs && $parse(selectAs);
26404             var viewValueFn = selectAsFn || valueFn;
26405             var trackByFn = trackBy && $parse(trackBy);
26406
26407             // Get the value by which we are going to track the option
26408             // if we have a trackFn then use that (passing scope and locals)
26409             // otherwise just hash the given viewValue
26410             var getTrackByValueFn = trackBy ?
26411                                       function(value, locals) { return trackByFn(scope, locals); } :
26412                                       function getHashOfValue(value) { return hashKey(value); };
26413             var getTrackByValue = function(value, key) {
26414               return getTrackByValueFn(value, getLocals(value, key));
26415             };
26416
26417             var displayFn = $parse(match[2] || match[1]);
26418             var groupByFn = $parse(match[3] || '');
26419             var disableWhenFn = $parse(match[4] || '');
26420             var valuesFn = $parse(match[8]);
26421
26422             var locals = {};
26423             var getLocals = keyName ? function(value, key) {
26424               locals[keyName] = key;
26425               locals[valueName] = value;
26426               return locals;
26427             } : function(value) {
26428               locals[valueName] = value;
26429               return locals;
26430             };
26431
26432
26433             function Option(selectValue, viewValue, label, group, disabled) {
26434               this.selectValue = selectValue;
26435               this.viewValue = viewValue;
26436               this.label = label;
26437               this.group = group;
26438               this.disabled = disabled;
26439             }
26440
26441             function getOptionValuesKeys(optionValues) {
26442               var optionValuesKeys;
26443
26444               if (!keyName && isArrayLike(optionValues)) {
26445                 optionValuesKeys = optionValues;
26446               } else {
26447                 // if object, extract keys, in enumeration order, unsorted
26448                 optionValuesKeys = [];
26449                 for (var itemKey in optionValues) {
26450                   if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
26451                     optionValuesKeys.push(itemKey);
26452                   }
26453                 }
26454               }
26455               return optionValuesKeys;
26456             }
26457
26458             return {
26459               trackBy: trackBy,
26460               getTrackByValue: getTrackByValue,
26461               getWatchables: $parse(valuesFn, function(optionValues) {
26462                 // Create a collection of things that we would like to watch (watchedArray)
26463                 // so that they can all be watched using a single $watchCollection
26464                 // that only runs the handler once if anything changes
26465                 var watchedArray = [];
26466                 optionValues = optionValues || [];
26467
26468                 var optionValuesKeys = getOptionValuesKeys(optionValues);
26469                 var optionValuesLength = optionValuesKeys.length;
26470                 for (var index = 0; index < optionValuesLength; index++) {
26471                   var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
26472                   var value = optionValues[key];
26473
26474                   var locals = getLocals(optionValues[key], key);
26475                   var selectValue = getTrackByValueFn(optionValues[key], locals);
26476                   watchedArray.push(selectValue);
26477
26478                   // Only need to watch the displayFn if there is a specific label expression
26479                   if (match[2] || match[1]) {
26480                     var label = displayFn(scope, locals);
26481                     watchedArray.push(label);
26482                   }
26483
26484                   // Only need to watch the disableWhenFn if there is a specific disable expression
26485                   if (match[4]) {
26486                     var disableWhen = disableWhenFn(scope, locals);
26487                     watchedArray.push(disableWhen);
26488                   }
26489                 }
26490                 return watchedArray;
26491               }),
26492
26493               getOptions: function() {
26494
26495                 var optionItems = [];
26496                 var selectValueMap = {};
26497
26498                 // The option values were already computed in the `getWatchables` fn,
26499                 // which must have been called to trigger `getOptions`
26500                 var optionValues = valuesFn(scope) || [];
26501                 var optionValuesKeys = getOptionValuesKeys(optionValues);
26502                 var optionValuesLength = optionValuesKeys.length;
26503
26504                 for (var index = 0; index < optionValuesLength; index++) {
26505                   var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
26506                   var value = optionValues[key];
26507                   var locals = getLocals(value, key);
26508                   var viewValue = viewValueFn(scope, locals);
26509                   var selectValue = getTrackByValueFn(viewValue, locals);
26510                   var label = displayFn(scope, locals);
26511                   var group = groupByFn(scope, locals);
26512                   var disabled = disableWhenFn(scope, locals);
26513                   var optionItem = new Option(selectValue, viewValue, label, group, disabled);
26514
26515                   optionItems.push(optionItem);
26516                   selectValueMap[selectValue] = optionItem;
26517                 }
26518
26519                 return {
26520                   items: optionItems,
26521                   selectValueMap: selectValueMap,
26522                   getOptionFromViewValue: function(value) {
26523                     return selectValueMap[getTrackByValue(value)];
26524                   },
26525                   getViewValueFromOption: function(option) {
26526                     // If the viewValue could be an object that may be mutated by the application,
26527                     // we need to make a copy and not return the reference to the value on the option.
26528                     return trackBy ? angular.copy(option.viewValue) : option.viewValue;
26529                   }
26530                 };
26531               }
26532             };
26533           }
26534
26535
26536           // we can't just jqLite('<option>') since jqLite is not smart enough
26537           // to create it in <select> and IE barfs otherwise.
26538           var optionTemplate = document.createElement('option'),
26539               optGroupTemplate = document.createElement('optgroup');
26540
26541
26542             function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
26543
26544               // if ngModel is not defined, we don't need to do anything
26545               var ngModelCtrl = ctrls[1];
26546               if (!ngModelCtrl) return;
26547
26548               var selectCtrl = ctrls[0];
26549               var multiple = attr.multiple;
26550
26551               // The emptyOption allows the application developer to provide their own custom "empty"
26552               // option when the viewValue does not match any of the option values.
26553               var emptyOption;
26554               for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
26555                 if (children[i].value === '') {
26556                   emptyOption = children.eq(i);
26557                   break;
26558                 }
26559               }
26560
26561               var providedEmptyOption = !!emptyOption;
26562
26563               var unknownOption = jqLite(optionTemplate.cloneNode(false));
26564               unknownOption.val('?');
26565
26566               var options;
26567               var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
26568
26569
26570               var renderEmptyOption = function() {
26571                 if (!providedEmptyOption) {
26572                   selectElement.prepend(emptyOption);
26573                 }
26574                 selectElement.val('');
26575                 emptyOption.prop('selected', true); // needed for IE
26576                 emptyOption.attr('selected', true);
26577               };
26578
26579               var removeEmptyOption = function() {
26580                 if (!providedEmptyOption) {
26581                   emptyOption.remove();
26582                 }
26583               };
26584
26585
26586               var renderUnknownOption = function() {
26587                 selectElement.prepend(unknownOption);
26588                 selectElement.val('?');
26589                 unknownOption.prop('selected', true); // needed for IE
26590                 unknownOption.attr('selected', true);
26591               };
26592
26593               var removeUnknownOption = function() {
26594                 unknownOption.remove();
26595               };
26596
26597               // Update the controller methods for multiple selectable options
26598               if (!multiple) {
26599
26600                 selectCtrl.writeValue = function writeNgOptionsValue(value) {
26601                   var option = options.getOptionFromViewValue(value);
26602
26603                   if (option && !option.disabled) {
26604                     if (selectElement[0].value !== option.selectValue) {
26605                       removeUnknownOption();
26606                       removeEmptyOption();
26607
26608                       selectElement[0].value = option.selectValue;
26609                       option.element.selected = true;
26610                       option.element.setAttribute('selected', 'selected');
26611                     }
26612                   } else {
26613                     if (value === null || providedEmptyOption) {
26614                       removeUnknownOption();
26615                       renderEmptyOption();
26616                     } else {
26617                       removeEmptyOption();
26618                       renderUnknownOption();
26619                     }
26620                   }
26621                 };
26622
26623                 selectCtrl.readValue = function readNgOptionsValue() {
26624
26625                   var selectedOption = options.selectValueMap[selectElement.val()];
26626
26627                   if (selectedOption && !selectedOption.disabled) {
26628                     removeEmptyOption();
26629                     removeUnknownOption();
26630                     return options.getViewValueFromOption(selectedOption);
26631                   }
26632                   return null;
26633                 };
26634
26635                 // If we are using `track by` then we must watch the tracked value on the model
26636                 // since ngModel only watches for object identity change
26637                 if (ngOptions.trackBy) {
26638                   scope.$watch(
26639                     function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
26640                     function() { ngModelCtrl.$render(); }
26641                   );
26642                 }
26643
26644               } else {
26645
26646                 ngModelCtrl.$isEmpty = function(value) {
26647                   return !value || value.length === 0;
26648                 };
26649
26650
26651                 selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
26652                   options.items.forEach(function(option) {
26653                     option.element.selected = false;
26654                   });
26655
26656                   if (value) {
26657                     value.forEach(function(item) {
26658                       var option = options.getOptionFromViewValue(item);
26659                       if (option && !option.disabled) option.element.selected = true;
26660                     });
26661                   }
26662                 };
26663
26664
26665                 selectCtrl.readValue = function readNgOptionsMultiple() {
26666                   var selectedValues = selectElement.val() || [],
26667                       selections = [];
26668
26669                   forEach(selectedValues, function(value) {
26670                     var option = options.selectValueMap[value];
26671                     if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
26672                   });
26673
26674                   return selections;
26675                 };
26676
26677                 // If we are using `track by` then we must watch these tracked values on the model
26678                 // since ngModel only watches for object identity change
26679                 if (ngOptions.trackBy) {
26680
26681                   scope.$watchCollection(function() {
26682                     if (isArray(ngModelCtrl.$viewValue)) {
26683                       return ngModelCtrl.$viewValue.map(function(value) {
26684                         return ngOptions.getTrackByValue(value);
26685                       });
26686                     }
26687                   }, function() {
26688                     ngModelCtrl.$render();
26689                   });
26690
26691                 }
26692               }
26693
26694
26695               if (providedEmptyOption) {
26696
26697                 // we need to remove it before calling selectElement.empty() because otherwise IE will
26698                 // remove the label from the element. wtf?
26699                 emptyOption.remove();
26700
26701                 // compile the element since there might be bindings in it
26702                 $compile(emptyOption)(scope);
26703
26704                 // remove the class, which is added automatically because we recompile the element and it
26705                 // becomes the compilation root
26706                 emptyOption.removeClass('ng-scope');
26707               } else {
26708                 emptyOption = jqLite(optionTemplate.cloneNode(false));
26709               }
26710
26711               // We need to do this here to ensure that the options object is defined
26712               // when we first hit it in writeNgOptionsValue
26713               updateOptions();
26714
26715               // We will re-render the option elements if the option values or labels change
26716               scope.$watchCollection(ngOptions.getWatchables, updateOptions);
26717
26718               // ------------------------------------------------------------------ //
26719
26720
26721               function updateOptionElement(option, element) {
26722                 option.element = element;
26723                 element.disabled = option.disabled;
26724                 // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
26725                 // selects in certain circumstances when multiple selects are next to each other and display
26726                 // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
26727                 // See https://github.com/angular/angular.js/issues/11314 for more info.
26728                 // This is unfortunately untestable with unit / e2e tests
26729                 if (option.label !== element.label) {
26730                   element.label = option.label;
26731                   element.textContent = option.label;
26732                 }
26733                 if (option.value !== element.value) element.value = option.selectValue;
26734               }
26735
26736               function addOrReuseElement(parent, current, type, templateElement) {
26737                 var element;
26738                 // Check whether we can reuse the next element
26739                 if (current && lowercase(current.nodeName) === type) {
26740                   // The next element is the right type so reuse it
26741                   element = current;
26742                 } else {
26743                   // The next element is not the right type so create a new one
26744                   element = templateElement.cloneNode(false);
26745                   if (!current) {
26746                     // There are no more elements so just append it to the select
26747                     parent.appendChild(element);
26748                   } else {
26749                     // The next element is not a group so insert the new one
26750                     parent.insertBefore(element, current);
26751                   }
26752                 }
26753                 return element;
26754               }
26755
26756
26757               function removeExcessElements(current) {
26758                 var next;
26759                 while (current) {
26760                   next = current.nextSibling;
26761                   jqLiteRemove(current);
26762                   current = next;
26763                 }
26764               }
26765
26766
26767               function skipEmptyAndUnknownOptions(current) {
26768                 var emptyOption_ = emptyOption && emptyOption[0];
26769                 var unknownOption_ = unknownOption && unknownOption[0];
26770
26771                 // We cannot rely on the extracted empty option being the same as the compiled empty option,
26772                 // because the compiled empty option might have been replaced by a comment because
26773                 // it had an "element" transclusion directive on it (such as ngIf)
26774                 if (emptyOption_ || unknownOption_) {
26775                   while (current &&
26776                         (current === emptyOption_ ||
26777                         current === unknownOption_ ||
26778                         current.nodeType === NODE_TYPE_COMMENT ||
26779                         current.value === '')) {
26780                     current = current.nextSibling;
26781                   }
26782                 }
26783                 return current;
26784               }
26785
26786
26787               function updateOptions() {
26788
26789                 var previousValue = options && selectCtrl.readValue();
26790
26791                 options = ngOptions.getOptions();
26792
26793                 var groupMap = {};
26794                 var currentElement = selectElement[0].firstChild;
26795
26796                 // Ensure that the empty option is always there if it was explicitly provided
26797                 if (providedEmptyOption) {
26798                   selectElement.prepend(emptyOption);
26799                 }
26800
26801                 currentElement = skipEmptyAndUnknownOptions(currentElement);
26802
26803                 options.items.forEach(function updateOption(option) {
26804                   var group;
26805                   var groupElement;
26806                   var optionElement;
26807
26808                   if (option.group) {
26809
26810                     // This option is to live in a group
26811                     // See if we have already created this group
26812                     group = groupMap[option.group];
26813
26814                     if (!group) {
26815
26816                       // We have not already created this group
26817                       groupElement = addOrReuseElement(selectElement[0],
26818                                                        currentElement,
26819                                                        'optgroup',
26820                                                        optGroupTemplate);
26821                       // Move to the next element
26822                       currentElement = groupElement.nextSibling;
26823
26824                       // Update the label on the group element
26825                       groupElement.label = option.group;
26826
26827                       // Store it for use later
26828                       group = groupMap[option.group] = {
26829                         groupElement: groupElement,
26830                         currentOptionElement: groupElement.firstChild
26831                       };
26832
26833                     }
26834
26835                     // So now we have a group for this option we add the option to the group
26836                     optionElement = addOrReuseElement(group.groupElement,
26837                                                       group.currentOptionElement,
26838                                                       'option',
26839                                                       optionTemplate);
26840                     updateOptionElement(option, optionElement);
26841                     // Move to the next element
26842                     group.currentOptionElement = optionElement.nextSibling;
26843
26844                   } else {
26845
26846                     // This option is not in a group
26847                     optionElement = addOrReuseElement(selectElement[0],
26848                                                       currentElement,
26849                                                       'option',
26850                                                       optionTemplate);
26851                     updateOptionElement(option, optionElement);
26852                     // Move to the next element
26853                     currentElement = optionElement.nextSibling;
26854                   }
26855                 });
26856
26857
26858                 // Now remove all excess options and group
26859                 Object.keys(groupMap).forEach(function(key) {
26860                   removeExcessElements(groupMap[key].currentOptionElement);
26861                 });
26862                 removeExcessElements(currentElement);
26863
26864                 ngModelCtrl.$render();
26865
26866                 // Check to see if the value has changed due to the update to the options
26867                 if (!ngModelCtrl.$isEmpty(previousValue)) {
26868                   var nextValue = selectCtrl.readValue();
26869                   if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
26870                     ngModelCtrl.$setViewValue(nextValue);
26871                     ngModelCtrl.$render();
26872                   }
26873                 }
26874
26875               }
26876           }
26877
26878           return {
26879             restrict: 'A',
26880             terminal: true,
26881             require: ['select', '?ngModel'],
26882             link: {
26883               pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
26884                 // Deactivate the SelectController.register method to prevent
26885                 // option directives from accidentally registering themselves
26886                 // (and unwanted $destroy handlers etc.)
26887                 ctrls[0].registerOption = noop;
26888               },
26889               post: ngOptionsPostLink
26890             }
26891           };
26892         }];
26893
26894         /**
26895          * @ngdoc directive
26896          * @name ngPluralize
26897          * @restrict EA
26898          *
26899          * @description
26900          * `ngPluralize` is a directive that displays messages according to en-US localization rules.
26901          * These rules are bundled with angular.js, but can be overridden
26902          * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
26903          * by specifying the mappings between
26904          * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26905          * and the strings to be displayed.
26906          *
26907          * # Plural categories and explicit number rules
26908          * There are two
26909          * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26910          * in Angular's default en-US locale: "one" and "other".
26911          *
26912          * While a plural category may match many numbers (for example, in en-US locale, "other" can match
26913          * any number that is not 1), an explicit number rule can only match one number. For example, the
26914          * explicit number rule for "3" matches the number 3. There are examples of plural categories
26915          * and explicit number rules throughout the rest of this documentation.
26916          *
26917          * # Configuring ngPluralize
26918          * You configure ngPluralize by providing 2 attributes: `count` and `when`.
26919          * You can also provide an optional attribute, `offset`.
26920          *
26921          * The value of the `count` attribute can be either a string or an {@link guide/expression
26922          * Angular expression}; these are evaluated on the current scope for its bound value.
26923          *
26924          * The `when` attribute specifies the mappings between plural categories and the actual
26925          * string to be displayed. The value of the attribute should be a JSON object.
26926          *
26927          * The following example shows how to configure ngPluralize:
26928          *
26929          * ```html
26930          * <ng-pluralize count="personCount"
26931                          when="{'0': 'Nobody is viewing.',
26932          *                      'one': '1 person is viewing.',
26933          *                      'other': '{} people are viewing.'}">
26934          * </ng-pluralize>
26935          *```
26936          *
26937          * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
26938          * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
26939          * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
26940          * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
26941          * show "a dozen people are viewing".
26942          *
26943          * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
26944          * into pluralized strings. In the previous example, Angular will replace `{}` with
26945          * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
26946          * for <span ng-non-bindable>{{numberExpression}}</span>.
26947          *
26948          * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
26949          * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
26950          *
26951          * # Configuring ngPluralize with offset
26952          * The `offset` attribute allows further customization of pluralized text, which can result in
26953          * a better user experience. For example, instead of the message "4 people are viewing this document",
26954          * you might display "John, Kate and 2 others are viewing this document".
26955          * The offset attribute allows you to offset a number by any desired value.
26956          * Let's take a look at an example:
26957          *
26958          * ```html
26959          * <ng-pluralize count="personCount" offset=2
26960          *               when="{'0': 'Nobody is viewing.',
26961          *                      '1': '{{person1}} is viewing.',
26962          *                      '2': '{{person1}} and {{person2}} are viewing.',
26963          *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
26964          *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
26965          * </ng-pluralize>
26966          * ```
26967          *
26968          * Notice that we are still using two plural categories(one, other), but we added
26969          * three explicit number rules 0, 1 and 2.
26970          * When one person, perhaps John, views the document, "John is viewing" will be shown.
26971          * When three people view the document, no explicit number rule is found, so
26972          * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
26973          * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
26974          * is shown.
26975          *
26976          * Note that when you specify offsets, you must provide explicit number rules for
26977          * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
26978          * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
26979          * plural categories "one" and "other".
26980          *
26981          * @param {string|expression} count The variable to be bound to.
26982          * @param {string} when The mapping between plural category to its corresponding strings.
26983          * @param {number=} offset Offset to deduct from the total number.
26984          *
26985          * @example
26986             <example module="pluralizeExample">
26987               <file name="index.html">
26988                 <script>
26989                   angular.module('pluralizeExample', [])
26990                     .controller('ExampleController', ['$scope', function($scope) {
26991                       $scope.person1 = 'Igor';
26992                       $scope.person2 = 'Misko';
26993                       $scope.personCount = 1;
26994                     }]);
26995                 </script>
26996                 <div ng-controller="ExampleController">
26997                   <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
26998                   <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
26999                   <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
27000
27001                   <!--- Example with simple pluralization rules for en locale --->
27002                   Without Offset:
27003                   <ng-pluralize count="personCount"
27004                                 when="{'0': 'Nobody is viewing.',
27005                                        'one': '1 person is viewing.',
27006                                        'other': '{} people are viewing.'}">
27007                   </ng-pluralize><br>
27008
27009                   <!--- Example with offset --->
27010                   With Offset(2):
27011                   <ng-pluralize count="personCount" offset=2
27012                                 when="{'0': 'Nobody is viewing.',
27013                                        '1': '{{person1}} is viewing.',
27014                                        '2': '{{person1}} and {{person2}} are viewing.',
27015                                        'one': '{{person1}}, {{person2}} and one other person are viewing.',
27016                                        'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
27017                   </ng-pluralize>
27018                 </div>
27019               </file>
27020               <file name="protractor.js" type="protractor">
27021                 it('should show correct pluralized string', function() {
27022                   var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
27023                   var withOffset = element.all(by.css('ng-pluralize')).get(1);
27024                   var countInput = element(by.model('personCount'));
27025
27026                   expect(withoutOffset.getText()).toEqual('1 person is viewing.');
27027                   expect(withOffset.getText()).toEqual('Igor is viewing.');
27028
27029                   countInput.clear();
27030                   countInput.sendKeys('0');
27031
27032                   expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
27033                   expect(withOffset.getText()).toEqual('Nobody is viewing.');
27034
27035                   countInput.clear();
27036                   countInput.sendKeys('2');
27037
27038                   expect(withoutOffset.getText()).toEqual('2 people are viewing.');
27039                   expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
27040
27041                   countInput.clear();
27042                   countInput.sendKeys('3');
27043
27044                   expect(withoutOffset.getText()).toEqual('3 people are viewing.');
27045                   expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
27046
27047                   countInput.clear();
27048                   countInput.sendKeys('4');
27049
27050                   expect(withoutOffset.getText()).toEqual('4 people are viewing.');
27051                   expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
27052                 });
27053                 it('should show data-bound names', function() {
27054                   var withOffset = element.all(by.css('ng-pluralize')).get(1);
27055                   var personCount = element(by.model('personCount'));
27056                   var person1 = element(by.model('person1'));
27057                   var person2 = element(by.model('person2'));
27058                   personCount.clear();
27059                   personCount.sendKeys('4');
27060                   person1.clear();
27061                   person1.sendKeys('Di');
27062                   person2.clear();
27063                   person2.sendKeys('Vojta');
27064                   expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
27065                 });
27066               </file>
27067             </example>
27068          */
27069         var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
27070           var BRACE = /{}/g,
27071               IS_WHEN = /^when(Minus)?(.+)$/;
27072
27073           return {
27074             link: function(scope, element, attr) {
27075               var numberExp = attr.count,
27076                   whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
27077                   offset = attr.offset || 0,
27078                   whens = scope.$eval(whenExp) || {},
27079                   whensExpFns = {},
27080                   startSymbol = $interpolate.startSymbol(),
27081                   endSymbol = $interpolate.endSymbol(),
27082                   braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
27083                   watchRemover = angular.noop,
27084                   lastCount;
27085
27086               forEach(attr, function(expression, attributeName) {
27087                 var tmpMatch = IS_WHEN.exec(attributeName);
27088                 if (tmpMatch) {
27089                   var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
27090                   whens[whenKey] = element.attr(attr.$attr[attributeName]);
27091                 }
27092               });
27093               forEach(whens, function(expression, key) {
27094                 whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
27095
27096               });
27097
27098               scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
27099                 var count = parseFloat(newVal);
27100                 var countIsNaN = isNaN(count);
27101
27102                 if (!countIsNaN && !(count in whens)) {
27103                   // If an explicit number rule such as 1, 2, 3... is defined, just use it.
27104                   // Otherwise, check it against pluralization rules in $locale service.
27105                   count = $locale.pluralCat(count - offset);
27106                 }
27107
27108                 // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
27109                 // In JS `NaN !== NaN`, so we have to exlicitly check.
27110                 if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
27111                   watchRemover();
27112                   var whenExpFn = whensExpFns[count];
27113                   if (isUndefined(whenExpFn)) {
27114                     if (newVal != null) {
27115                       $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
27116                     }
27117                     watchRemover = noop;
27118                     updateElementText();
27119                   } else {
27120                     watchRemover = scope.$watch(whenExpFn, updateElementText);
27121                   }
27122                   lastCount = count;
27123                 }
27124               });
27125
27126               function updateElementText(newText) {
27127                 element.text(newText || '');
27128               }
27129             }
27130           };
27131         }];
27132
27133         /**
27134          * @ngdoc directive
27135          * @name ngRepeat
27136          * @multiElement
27137          *
27138          * @description
27139          * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
27140          * instance gets its own scope, where the given loop variable is set to the current collection item,
27141          * and `$index` is set to the item index or key.
27142          *
27143          * Special properties are exposed on the local scope of each template instance, including:
27144          *
27145          * | Variable  | Type            | Details                                                                     |
27146          * |-----------|-----------------|-----------------------------------------------------------------------------|
27147          * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
27148          * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
27149          * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
27150          * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
27151          * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
27152          * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
27153          *
27154          * <div class="alert alert-info">
27155          *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
27156          *   This may be useful when, for instance, nesting ngRepeats.
27157          * </div>
27158          *
27159          *
27160          * # Iterating over object properties
27161          *
27162          * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
27163          * syntax:
27164          *
27165          * ```js
27166          * <div ng-repeat="(key, value) in myObj"> ... </div>
27167          * ```
27168          *
27169          * You need to be aware that the JavaScript specification does not define the order of keys
27170          * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
27171          * used to sort the keys alphabetically.)
27172          *
27173          * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
27174          * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
27175          * keys in the order in which they were defined, although there are exceptions when keys are deleted
27176          * 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).
27177          *
27178          * If this is not desired, the recommended workaround is to convert your object into an array
27179          * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
27180          * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
27181          * or implement a `$watch` on the object yourself.
27182          *
27183          *
27184          * # Tracking and Duplicates
27185          *
27186          * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
27187          * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
27188          *
27189          * * When an item is added, a new instance of the template is added to the DOM.
27190          * * When an item is removed, its template instance is removed from the DOM.
27191          * * When items are reordered, their respective templates are reordered in the DOM.
27192          *
27193          * To minimize creation of DOM elements, `ngRepeat` uses a function
27194          * to "keep track" of all items in the collection and their corresponding DOM elements.
27195          * For example, if an item is added to the collection, ngRepeat will know that all other items
27196          * already have DOM elements, and will not re-render them.
27197          *
27198          * The default tracking function (which tracks items by their identity) does not allow
27199          * duplicate items in arrays. This is because when there are duplicates, it is not possible
27200          * to maintain a one-to-one mapping between collection items and DOM elements.
27201          *
27202          * If you do need to repeat duplicate items, you can substitute the default tracking behavior
27203          * with your own using the `track by` expression.
27204          *
27205          * For example, you may track items by the index of each item in the collection, using the
27206          * special scope property `$index`:
27207          * ```html
27208          *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
27209          *      {{n}}
27210          *    </div>
27211          * ```
27212          *
27213          * You may also use arbitrary expressions in `track by`, including references to custom functions
27214          * on the scope:
27215          * ```html
27216          *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
27217          *      {{n}}
27218          *    </div>
27219          * ```
27220          *
27221          * <div class="alert alert-success">
27222          * If you are working with objects that have an identifier property, you should track
27223          * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
27224          * will not have to rebuild the DOM elements for items it has already rendered, even if the
27225          * JavaScript objects in the collection have been substituted for new ones. For large collections,
27226          * this signifincantly improves rendering performance. If you don't have a unique identifier,
27227          * `track by $index` can also provide a performance boost.
27228          * </div>
27229          * ```html
27230          *    <div ng-repeat="model in collection track by model.id">
27231          *      {{model.name}}
27232          *    </div>
27233          * ```
27234          *
27235          * When no `track by` expression is provided, it is equivalent to tracking by the built-in
27236          * `$id` function, which tracks items by their identity:
27237          * ```html
27238          *    <div ng-repeat="obj in collection track by $id(obj)">
27239          *      {{obj.prop}}
27240          *    </div>
27241          * ```
27242          *
27243          * <div class="alert alert-warning">
27244          * **Note:** `track by` must always be the last expression:
27245          * </div>
27246          * ```
27247          * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
27248          *     {{model.name}}
27249          * </div>
27250          * ```
27251          *
27252          * # Special repeat start and end points
27253          * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
27254          * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
27255          * 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)
27256          * up to and including the ending HTML tag where **ng-repeat-end** is placed.
27257          *
27258          * The example below makes use of this feature:
27259          * ```html
27260          *   <header ng-repeat-start="item in items">
27261          *     Header {{ item }}
27262          *   </header>
27263          *   <div class="body">
27264          *     Body {{ item }}
27265          *   </div>
27266          *   <footer ng-repeat-end>
27267          *     Footer {{ item }}
27268          *   </footer>
27269          * ```
27270          *
27271          * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
27272          * ```html
27273          *   <header>
27274          *     Header A
27275          *   </header>
27276          *   <div class="body">
27277          *     Body A
27278          *   </div>
27279          *   <footer>
27280          *     Footer A
27281          *   </footer>
27282          *   <header>
27283          *     Header B
27284          *   </header>
27285          *   <div class="body">
27286          *     Body B
27287          *   </div>
27288          *   <footer>
27289          *     Footer B
27290          *   </footer>
27291          * ```
27292          *
27293          * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
27294          * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
27295          *
27296          * @animations
27297          * **.enter** - when a new item is added to the list or when an item is revealed after a filter
27298          *
27299          * **.leave** - when an item is removed from the list or when an item is filtered out
27300          *
27301          * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
27302          *
27303          * @element ANY
27304          * @scope
27305          * @priority 1000
27306          * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
27307          *   formats are currently supported:
27308          *
27309          *   * `variable in expression` – where variable is the user defined loop variable and `expression`
27310          *     is a scope expression giving the collection to enumerate.
27311          *
27312          *     For example: `album in artist.albums`.
27313          *
27314          *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
27315          *     and `expression` is the scope expression giving the collection to enumerate.
27316          *
27317          *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
27318          *
27319          *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
27320          *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
27321          *     is specified, ng-repeat associates elements by identity. It is an error to have
27322          *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
27323          *     mapped to the same DOM element, which is not possible.)
27324          *
27325          *     Note that the tracking expression must come last, after any filters, and the alias expression.
27326          *
27327          *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
27328          *     will be associated by item identity in the array.
27329          *
27330          *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
27331          *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
27332          *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
27333          *     element in the same way in the DOM.
27334          *
27335          *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
27336          *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
27337          *     property is same.
27338          *
27339          *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
27340          *     to items in conjunction with a tracking expression.
27341          *
27342          *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
27343          *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
27344          *     when a filter is active on the repeater, but the filtered result set is empty.
27345          *
27346          *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
27347          *     the items have been processed through the filter.
27348          *
27349          *     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
27350          *     (and not as operator, inside an expression).
27351          *
27352          *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
27353          *
27354          * @example
27355          * This example initializes the scope to a list of names and
27356          * then uses `ngRepeat` to display every person:
27357           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27358             <file name="index.html">
27359               <div ng-init="friends = [
27360                 {name:'John', age:25, gender:'boy'},
27361                 {name:'Jessie', age:30, gender:'girl'},
27362                 {name:'Johanna', age:28, gender:'girl'},
27363                 {name:'Joy', age:15, gender:'girl'},
27364                 {name:'Mary', age:28, gender:'girl'},
27365                 {name:'Peter', age:95, gender:'boy'},
27366                 {name:'Sebastian', age:50, gender:'boy'},
27367                 {name:'Erika', age:27, gender:'girl'},
27368                 {name:'Patrick', age:40, gender:'boy'},
27369                 {name:'Samantha', age:60, gender:'girl'}
27370               ]">
27371                 I have {{friends.length}} friends. They are:
27372                 <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
27373                 <ul class="example-animate-container">
27374                   <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
27375                     [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
27376                   </li>
27377                   <li class="animate-repeat" ng-if="results.length == 0">
27378                     <strong>No results found...</strong>
27379                   </li>
27380                 </ul>
27381               </div>
27382             </file>
27383             <file name="animations.css">
27384               .example-animate-container {
27385                 background:white;
27386                 border:1px solid black;
27387                 list-style:none;
27388                 margin:0;
27389                 padding:0 10px;
27390               }
27391
27392               .animate-repeat {
27393                 line-height:40px;
27394                 list-style:none;
27395                 box-sizing:border-box;
27396               }
27397
27398               .animate-repeat.ng-move,
27399               .animate-repeat.ng-enter,
27400               .animate-repeat.ng-leave {
27401                 transition:all linear 0.5s;
27402               }
27403
27404               .animate-repeat.ng-leave.ng-leave-active,
27405               .animate-repeat.ng-move,
27406               .animate-repeat.ng-enter {
27407                 opacity:0;
27408                 max-height:0;
27409               }
27410
27411               .animate-repeat.ng-leave,
27412               .animate-repeat.ng-move.ng-move-active,
27413               .animate-repeat.ng-enter.ng-enter-active {
27414                 opacity:1;
27415                 max-height:40px;
27416               }
27417             </file>
27418             <file name="protractor.js" type="protractor">
27419               var friends = element.all(by.repeater('friend in friends'));
27420
27421               it('should render initial data set', function() {
27422                 expect(friends.count()).toBe(10);
27423                 expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
27424                 expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
27425                 expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
27426                 expect(element(by.binding('friends.length')).getText())
27427                     .toMatch("I have 10 friends. They are:");
27428               });
27429
27430                it('should update repeater when filter predicate changes', function() {
27431                  expect(friends.count()).toBe(10);
27432
27433                  element(by.model('q')).sendKeys('ma');
27434
27435                  expect(friends.count()).toBe(2);
27436                  expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
27437                  expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
27438                });
27439               </file>
27440             </example>
27441          */
27442         var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
27443           var NG_REMOVED = '$$NG_REMOVED';
27444           var ngRepeatMinErr = minErr('ngRepeat');
27445
27446           var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
27447             // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
27448             scope[valueIdentifier] = value;
27449             if (keyIdentifier) scope[keyIdentifier] = key;
27450             scope.$index = index;
27451             scope.$first = (index === 0);
27452             scope.$last = (index === (arrayLength - 1));
27453             scope.$middle = !(scope.$first || scope.$last);
27454             // jshint bitwise: false
27455             scope.$odd = !(scope.$even = (index&1) === 0);
27456             // jshint bitwise: true
27457           };
27458
27459           var getBlockStart = function(block) {
27460             return block.clone[0];
27461           };
27462
27463           var getBlockEnd = function(block) {
27464             return block.clone[block.clone.length - 1];
27465           };
27466
27467
27468           return {
27469             restrict: 'A',
27470             multiElement: true,
27471             transclude: 'element',
27472             priority: 1000,
27473             terminal: true,
27474             $$tlb: true,
27475             compile: function ngRepeatCompile($element, $attr) {
27476               var expression = $attr.ngRepeat;
27477               var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
27478
27479               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*$/);
27480
27481               if (!match) {
27482                 throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
27483                     expression);
27484               }
27485
27486               var lhs = match[1];
27487               var rhs = match[2];
27488               var aliasAs = match[3];
27489               var trackByExp = match[4];
27490
27491               match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
27492
27493               if (!match) {
27494                 throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
27495                     lhs);
27496               }
27497               var valueIdentifier = match[3] || match[1];
27498               var keyIdentifier = match[2];
27499
27500               if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
27501                   /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
27502                 throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
27503                   aliasAs);
27504               }
27505
27506               var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
27507               var hashFnLocals = {$id: hashKey};
27508
27509               if (trackByExp) {
27510                 trackByExpGetter = $parse(trackByExp);
27511               } else {
27512                 trackByIdArrayFn = function(key, value) {
27513                   return hashKey(value);
27514                 };
27515                 trackByIdObjFn = function(key) {
27516                   return key;
27517                 };
27518               }
27519
27520               return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
27521
27522                 if (trackByExpGetter) {
27523                   trackByIdExpFn = function(key, value, index) {
27524                     // assign key, value, and $index to the locals so that they can be used in hash functions
27525                     if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
27526                     hashFnLocals[valueIdentifier] = value;
27527                     hashFnLocals.$index = index;
27528                     return trackByExpGetter($scope, hashFnLocals);
27529                   };
27530                 }
27531
27532                 // Store a list of elements from previous run. This is a hash where key is the item from the
27533                 // iterator, and the value is objects with following properties.
27534                 //   - scope: bound scope
27535                 //   - element: previous element.
27536                 //   - index: position
27537                 //
27538                 // We are using no-proto object so that we don't need to guard against inherited props via
27539                 // hasOwnProperty.
27540                 var lastBlockMap = createMap();
27541
27542                 //watch props
27543                 $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
27544                   var index, length,
27545                       previousNode = $element[0],     // node that cloned nodes should be inserted after
27546                                                       // initialized to the comment node anchor
27547                       nextNode,
27548                       // Same as lastBlockMap but it has the current state. It will become the
27549                       // lastBlockMap on the next iteration.
27550                       nextBlockMap = createMap(),
27551                       collectionLength,
27552                       key, value, // key/value of iteration
27553                       trackById,
27554                       trackByIdFn,
27555                       collectionKeys,
27556                       block,       // last object information {scope, element, id}
27557                       nextBlockOrder,
27558                       elementsToRemove;
27559
27560                   if (aliasAs) {
27561                     $scope[aliasAs] = collection;
27562                   }
27563
27564                   if (isArrayLike(collection)) {
27565                     collectionKeys = collection;
27566                     trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
27567                   } else {
27568                     trackByIdFn = trackByIdExpFn || trackByIdObjFn;
27569                     // if object, extract keys, in enumeration order, unsorted
27570                     collectionKeys = [];
27571                     for (var itemKey in collection) {
27572                       if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
27573                         collectionKeys.push(itemKey);
27574                       }
27575                     }
27576                   }
27577
27578                   collectionLength = collectionKeys.length;
27579                   nextBlockOrder = new Array(collectionLength);
27580
27581                   // locate existing items
27582                   for (index = 0; index < collectionLength; index++) {
27583                     key = (collection === collectionKeys) ? index : collectionKeys[index];
27584                     value = collection[key];
27585                     trackById = trackByIdFn(key, value, index);
27586                     if (lastBlockMap[trackById]) {
27587                       // found previously seen block
27588                       block = lastBlockMap[trackById];
27589                       delete lastBlockMap[trackById];
27590                       nextBlockMap[trackById] = block;
27591                       nextBlockOrder[index] = block;
27592                     } else if (nextBlockMap[trackById]) {
27593                       // if collision detected. restore lastBlockMap and throw an error
27594                       forEach(nextBlockOrder, function(block) {
27595                         if (block && block.scope) lastBlockMap[block.id] = block;
27596                       });
27597                       throw ngRepeatMinErr('dupes',
27598                           "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
27599                           expression, trackById, value);
27600                     } else {
27601                       // new never before seen block
27602                       nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
27603                       nextBlockMap[trackById] = true;
27604                     }
27605                   }
27606
27607                   // remove leftover items
27608                   for (var blockKey in lastBlockMap) {
27609                     block = lastBlockMap[blockKey];
27610                     elementsToRemove = getBlockNodes(block.clone);
27611                     $animate.leave(elementsToRemove);
27612                     if (elementsToRemove[0].parentNode) {
27613                       // if the element was not removed yet because of pending animation, mark it as deleted
27614                       // so that we can ignore it later
27615                       for (index = 0, length = elementsToRemove.length; index < length; index++) {
27616                         elementsToRemove[index][NG_REMOVED] = true;
27617                       }
27618                     }
27619                     block.scope.$destroy();
27620                   }
27621
27622                   // we are not using forEach for perf reasons (trying to avoid #call)
27623                   for (index = 0; index < collectionLength; index++) {
27624                     key = (collection === collectionKeys) ? index : collectionKeys[index];
27625                     value = collection[key];
27626                     block = nextBlockOrder[index];
27627
27628                     if (block.scope) {
27629                       // if we have already seen this object, then we need to reuse the
27630                       // associated scope/element
27631
27632                       nextNode = previousNode;
27633
27634                       // skip nodes that are already pending removal via leave animation
27635                       do {
27636                         nextNode = nextNode.nextSibling;
27637                       } while (nextNode && nextNode[NG_REMOVED]);
27638
27639                       if (getBlockStart(block) != nextNode) {
27640                         // existing item which got moved
27641                         $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
27642                       }
27643                       previousNode = getBlockEnd(block);
27644                       updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
27645                     } else {
27646                       // new item which we don't know about
27647                       $transclude(function ngRepeatTransclude(clone, scope) {
27648                         block.scope = scope;
27649                         // http://jsperf.com/clone-vs-createcomment
27650                         var endNode = ngRepeatEndComment.cloneNode(false);
27651                         clone[clone.length++] = endNode;
27652
27653                         // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
27654                         $animate.enter(clone, null, jqLite(previousNode));
27655                         previousNode = endNode;
27656                         // Note: We only need the first/last node of the cloned nodes.
27657                         // However, we need to keep the reference to the jqlite wrapper as it might be changed later
27658                         // by a directive with templateUrl when its template arrives.
27659                         block.clone = clone;
27660                         nextBlockMap[block.id] = block;
27661                         updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
27662                       });
27663                     }
27664                   }
27665                   lastBlockMap = nextBlockMap;
27666                 });
27667               };
27668             }
27669           };
27670         }];
27671
27672         var NG_HIDE_CLASS = 'ng-hide';
27673         var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
27674         /**
27675          * @ngdoc directive
27676          * @name ngShow
27677          * @multiElement
27678          *
27679          * @description
27680          * The `ngShow` directive shows or hides the given HTML element based on the expression
27681          * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
27682          * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27683          * in AngularJS and sets the display style to none (using an !important flag).
27684          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27685          *
27686          * ```html
27687          * <!-- when $scope.myValue is truthy (element is visible) -->
27688          * <div ng-show="myValue"></div>
27689          *
27690          * <!-- when $scope.myValue is falsy (element is hidden) -->
27691          * <div ng-show="myValue" class="ng-hide"></div>
27692          * ```
27693          *
27694          * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
27695          * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
27696          * from the element causing the element not to appear hidden.
27697          *
27698          * ## Why is !important used?
27699          *
27700          * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27701          * can be easily overridden by heavier selectors. For example, something as simple
27702          * as changing the display style on a HTML list item would make hidden elements appear visible.
27703          * This also becomes a bigger issue when dealing with CSS frameworks.
27704          *
27705          * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27706          * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27707          * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27708          *
27709          * ### Overriding `.ng-hide`
27710          *
27711          * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27712          * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27713          * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
27714          * with extra animation classes that can be added.
27715          *
27716          * ```css
27717          * .ng-hide:not(.ng-hide-animate) {
27718          *   /&#42; this is just another form of hiding an element &#42;/
27719          *   display: block!important;
27720          *   position: absolute;
27721          *   top: -9999px;
27722          *   left: -9999px;
27723          * }
27724          * ```
27725          *
27726          * By default you don't need to override in CSS anything and the animations will work around the display style.
27727          *
27728          * ## A note about animations with `ngShow`
27729          *
27730          * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27731          * is true and false. This system works like the animation system present with ngClass except that
27732          * you must also include the !important flag to override the display property
27733          * so that you can perform an animation when the element is hidden during the time of the animation.
27734          *
27735          * ```css
27736          * //
27737          * //a working example can be found at the bottom of this page
27738          * //
27739          * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27740          *   /&#42; this is required as of 1.3x to properly
27741          *      apply all styling in a show/hide animation &#42;/
27742          *   transition: 0s linear all;
27743          * }
27744          *
27745          * .my-element.ng-hide-add-active,
27746          * .my-element.ng-hide-remove-active {
27747          *   /&#42; the transition is defined in the active class &#42;/
27748          *   transition: 1s linear all;
27749          * }
27750          *
27751          * .my-element.ng-hide-add { ... }
27752          * .my-element.ng-hide-add.ng-hide-add-active { ... }
27753          * .my-element.ng-hide-remove { ... }
27754          * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27755          * ```
27756          *
27757          * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27758          * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27759          *
27760          * @animations
27761          * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
27762          * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
27763          *
27764          * @element ANY
27765          * @param {expression} ngShow If the {@link guide/expression expression} is truthy
27766          *     then the element is shown or hidden respectively.
27767          *
27768          * @example
27769           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27770             <file name="index.html">
27771               Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
27772               <div>
27773                 Show:
27774                 <div class="check-element animate-show" ng-show="checked">
27775                   <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27776                 </div>
27777               </div>
27778               <div>
27779                 Hide:
27780                 <div class="check-element animate-show" ng-hide="checked">
27781                   <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27782                 </div>
27783               </div>
27784             </file>
27785             <file name="glyphicons.css">
27786               @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27787             </file>
27788             <file name="animations.css">
27789               .animate-show {
27790                 line-height: 20px;
27791                 opacity: 1;
27792                 padding: 10px;
27793                 border: 1px solid black;
27794                 background: white;
27795               }
27796
27797               .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
27798                 transition: all linear 0.5s;
27799               }
27800
27801               .animate-show.ng-hide {
27802                 line-height: 0;
27803                 opacity: 0;
27804                 padding: 0 10px;
27805               }
27806
27807               .check-element {
27808                 padding: 10px;
27809                 border: 1px solid black;
27810                 background: white;
27811               }
27812             </file>
27813             <file name="protractor.js" type="protractor">
27814               var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27815               var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27816
27817               it('should check ng-show / ng-hide', function() {
27818                 expect(thumbsUp.isDisplayed()).toBeFalsy();
27819                 expect(thumbsDown.isDisplayed()).toBeTruthy();
27820
27821                 element(by.model('checked')).click();
27822
27823                 expect(thumbsUp.isDisplayed()).toBeTruthy();
27824                 expect(thumbsDown.isDisplayed()).toBeFalsy();
27825               });
27826             </file>
27827           </example>
27828          */
27829         var ngShowDirective = ['$animate', function($animate) {
27830           return {
27831             restrict: 'A',
27832             multiElement: true,
27833             link: function(scope, element, attr) {
27834               scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
27835                 // we're adding a temporary, animation-specific class for ng-hide since this way
27836                 // we can control when the element is actually displayed on screen without having
27837                 // to have a global/greedy CSS selector that breaks when other animations are run.
27838                 // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
27839                 $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
27840                   tempClasses: NG_HIDE_IN_PROGRESS_CLASS
27841                 });
27842               });
27843             }
27844           };
27845         }];
27846
27847
27848         /**
27849          * @ngdoc directive
27850          * @name ngHide
27851          * @multiElement
27852          *
27853          * @description
27854          * The `ngHide` directive shows or hides the given HTML element based on the expression
27855          * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
27856          * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27857          * in AngularJS and sets the display style to none (using an !important flag).
27858          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27859          *
27860          * ```html
27861          * <!-- when $scope.myValue is truthy (element is hidden) -->
27862          * <div ng-hide="myValue" class="ng-hide"></div>
27863          *
27864          * <!-- when $scope.myValue is falsy (element is visible) -->
27865          * <div ng-hide="myValue"></div>
27866          * ```
27867          *
27868          * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
27869          * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
27870          * from the element causing the element not to appear hidden.
27871          *
27872          * ## Why is !important used?
27873          *
27874          * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27875          * can be easily overridden by heavier selectors. For example, something as simple
27876          * as changing the display style on a HTML list item would make hidden elements appear visible.
27877          * This also becomes a bigger issue when dealing with CSS frameworks.
27878          *
27879          * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27880          * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27881          * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27882          *
27883          * ### Overriding `.ng-hide`
27884          *
27885          * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27886          * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27887          * class in CSS:
27888          *
27889          * ```css
27890          * .ng-hide {
27891          *   /&#42; this is just another form of hiding an element &#42;/
27892          *   display: block!important;
27893          *   position: absolute;
27894          *   top: -9999px;
27895          *   left: -9999px;
27896          * }
27897          * ```
27898          *
27899          * By default you don't need to override in CSS anything and the animations will work around the display style.
27900          *
27901          * ## A note about animations with `ngHide`
27902          *
27903          * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27904          * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
27905          * CSS class is added and removed for you instead of your own CSS class.
27906          *
27907          * ```css
27908          * //
27909          * //a working example can be found at the bottom of this page
27910          * //
27911          * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27912          *   transition: 0.5s linear all;
27913          * }
27914          *
27915          * .my-element.ng-hide-add { ... }
27916          * .my-element.ng-hide-add.ng-hide-add-active { ... }
27917          * .my-element.ng-hide-remove { ... }
27918          * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27919          * ```
27920          *
27921          * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27922          * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27923          *
27924          * @animations
27925          * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
27926          * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
27927          *
27928          * @element ANY
27929          * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
27930          *     the element is shown or hidden respectively.
27931          *
27932          * @example
27933           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27934             <file name="index.html">
27935               Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
27936               <div>
27937                 Show:
27938                 <div class="check-element animate-hide" ng-show="checked">
27939                   <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27940                 </div>
27941               </div>
27942               <div>
27943                 Hide:
27944                 <div class="check-element animate-hide" ng-hide="checked">
27945                   <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27946                 </div>
27947               </div>
27948             </file>
27949             <file name="glyphicons.css">
27950               @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27951             </file>
27952             <file name="animations.css">
27953               .animate-hide {
27954                 transition: all linear 0.5s;
27955                 line-height: 20px;
27956                 opacity: 1;
27957                 padding: 10px;
27958                 border: 1px solid black;
27959                 background: white;
27960               }
27961
27962               .animate-hide.ng-hide {
27963                 line-height: 0;
27964                 opacity: 0;
27965                 padding: 0 10px;
27966               }
27967
27968               .check-element {
27969                 padding: 10px;
27970                 border: 1px solid black;
27971                 background: white;
27972               }
27973             </file>
27974             <file name="protractor.js" type="protractor">
27975               var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27976               var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27977
27978               it('should check ng-show / ng-hide', function() {
27979                 expect(thumbsUp.isDisplayed()).toBeFalsy();
27980                 expect(thumbsDown.isDisplayed()).toBeTruthy();
27981
27982                 element(by.model('checked')).click();
27983
27984                 expect(thumbsUp.isDisplayed()).toBeTruthy();
27985                 expect(thumbsDown.isDisplayed()).toBeFalsy();
27986               });
27987             </file>
27988           </example>
27989          */
27990         var ngHideDirective = ['$animate', function($animate) {
27991           return {
27992             restrict: 'A',
27993             multiElement: true,
27994             link: function(scope, element, attr) {
27995               scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
27996                 // The comment inside of the ngShowDirective explains why we add and
27997                 // remove a temporary class for the show/hide animation
27998                 $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
27999                   tempClasses: NG_HIDE_IN_PROGRESS_CLASS
28000                 });
28001               });
28002             }
28003           };
28004         }];
28005
28006         /**
28007          * @ngdoc directive
28008          * @name ngStyle
28009          * @restrict AC
28010          *
28011          * @description
28012          * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
28013          *
28014          * @element ANY
28015          * @param {expression} ngStyle
28016          *
28017          * {@link guide/expression Expression} which evals to an
28018          * object whose keys are CSS style names and values are corresponding values for those CSS
28019          * keys.
28020          *
28021          * Since some CSS style names are not valid keys for an object, they must be quoted.
28022          * See the 'background-color' style in the example below.
28023          *
28024          * @example
28025            <example>
28026              <file name="index.html">
28027                 <input type="button" value="set color" ng-click="myStyle={color:'red'}">
28028                 <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
28029                 <input type="button" value="clear" ng-click="myStyle={}">
28030                 <br/>
28031                 <span ng-style="myStyle">Sample Text</span>
28032                 <pre>myStyle={{myStyle}}</pre>
28033              </file>
28034              <file name="style.css">
28035                span {
28036                  color: black;
28037                }
28038              </file>
28039              <file name="protractor.js" type="protractor">
28040                var colorSpan = element(by.css('span'));
28041
28042                it('should check ng-style', function() {
28043                  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
28044                  element(by.css('input[value=\'set color\']')).click();
28045                  expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
28046                  element(by.css('input[value=clear]')).click();
28047                  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
28048                });
28049              </file>
28050            </example>
28051          */
28052         var ngStyleDirective = ngDirective(function(scope, element, attr) {
28053           scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
28054             if (oldStyles && (newStyles !== oldStyles)) {
28055               forEach(oldStyles, function(val, style) { element.css(style, '');});
28056             }
28057             if (newStyles) element.css(newStyles);
28058           }, true);
28059         });
28060
28061         /**
28062          * @ngdoc directive
28063          * @name ngSwitch
28064          * @restrict EA
28065          *
28066          * @description
28067          * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
28068          * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
28069          * as specified in the template.
28070          *
28071          * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
28072          * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
28073          * matches the value obtained from the evaluated expression. In other words, you define a container element
28074          * (where you place the directive), place an expression on the **`on="..."` attribute**
28075          * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
28076          * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
28077          * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
28078          * attribute is displayed.
28079          *
28080          * <div class="alert alert-info">
28081          * Be aware that the attribute values to match against cannot be expressions. They are interpreted
28082          * as literal string values to match against.
28083          * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
28084          * value of the expression `$scope.someVal`.
28085          * </div>
28086
28087          * @animations
28088          * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
28089          * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
28090          *
28091          * @usage
28092          *
28093          * ```
28094          * <ANY ng-switch="expression">
28095          *   <ANY ng-switch-when="matchValue1">...</ANY>
28096          *   <ANY ng-switch-when="matchValue2">...</ANY>
28097          *   <ANY ng-switch-default>...</ANY>
28098          * </ANY>
28099          * ```
28100          *
28101          *
28102          * @scope
28103          * @priority 1200
28104          * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
28105          * On child elements add:
28106          *
28107          * * `ngSwitchWhen`: the case statement to match against. If match then this
28108          *   case will be displayed. If the same match appears multiple times, all the
28109          *   elements will be displayed.
28110          * * `ngSwitchDefault`: the default case when no other case match. If there
28111          *   are multiple default cases, all of them will be displayed when no other
28112          *   case match.
28113          *
28114          *
28115          * @example
28116           <example module="switchExample" deps="angular-animate.js" animations="true">
28117             <file name="index.html">
28118               <div ng-controller="ExampleController">
28119                 <select ng-model="selection" ng-options="item for item in items">
28120                 </select>
28121                 <code>selection={{selection}}</code>
28122                 <hr/>
28123                 <div class="animate-switch-container"
28124                   ng-switch on="selection">
28125                     <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
28126                     <div class="animate-switch" ng-switch-when="home">Home Span</div>
28127                     <div class="animate-switch" ng-switch-default>default</div>
28128                 </div>
28129               </div>
28130             </file>
28131             <file name="script.js">
28132               angular.module('switchExample', ['ngAnimate'])
28133                 .controller('ExampleController', ['$scope', function($scope) {
28134                   $scope.items = ['settings', 'home', 'other'];
28135                   $scope.selection = $scope.items[0];
28136                 }]);
28137             </file>
28138             <file name="animations.css">
28139               .animate-switch-container {
28140                 position:relative;
28141                 background:white;
28142                 border:1px solid black;
28143                 height:40px;
28144                 overflow:hidden;
28145               }
28146
28147               .animate-switch {
28148                 padding:10px;
28149               }
28150
28151               .animate-switch.ng-animate {
28152                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
28153
28154                 position:absolute;
28155                 top:0;
28156                 left:0;
28157                 right:0;
28158                 bottom:0;
28159               }
28160
28161               .animate-switch.ng-leave.ng-leave-active,
28162               .animate-switch.ng-enter {
28163                 top:-50px;
28164               }
28165               .animate-switch.ng-leave,
28166               .animate-switch.ng-enter.ng-enter-active {
28167                 top:0;
28168               }
28169             </file>
28170             <file name="protractor.js" type="protractor">
28171               var switchElem = element(by.css('[ng-switch]'));
28172               var select = element(by.model('selection'));
28173
28174               it('should start in settings', function() {
28175                 expect(switchElem.getText()).toMatch(/Settings Div/);
28176               });
28177               it('should change to home', function() {
28178                 select.all(by.css('option')).get(1).click();
28179                 expect(switchElem.getText()).toMatch(/Home Span/);
28180               });
28181               it('should select default', function() {
28182                 select.all(by.css('option')).get(2).click();
28183                 expect(switchElem.getText()).toMatch(/default/);
28184               });
28185             </file>
28186           </example>
28187          */
28188         var ngSwitchDirective = ['$animate', function($animate) {
28189           return {
28190             require: 'ngSwitch',
28191
28192             // asks for $scope to fool the BC controller module
28193             controller: ['$scope', function ngSwitchController() {
28194              this.cases = {};
28195             }],
28196             link: function(scope, element, attr, ngSwitchController) {
28197               var watchExpr = attr.ngSwitch || attr.on,
28198                   selectedTranscludes = [],
28199                   selectedElements = [],
28200                   previousLeaveAnimations = [],
28201                   selectedScopes = [];
28202
28203               var spliceFactory = function(array, index) {
28204                   return function() { array.splice(index, 1); };
28205               };
28206
28207               scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
28208                 var i, ii;
28209                 for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
28210                   $animate.cancel(previousLeaveAnimations[i]);
28211                 }
28212                 previousLeaveAnimations.length = 0;
28213
28214                 for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
28215                   var selected = getBlockNodes(selectedElements[i].clone);
28216                   selectedScopes[i].$destroy();
28217                   var promise = previousLeaveAnimations[i] = $animate.leave(selected);
28218                   promise.then(spliceFactory(previousLeaveAnimations, i));
28219                 }
28220
28221                 selectedElements.length = 0;
28222                 selectedScopes.length = 0;
28223
28224                 if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
28225                   forEach(selectedTranscludes, function(selectedTransclude) {
28226                     selectedTransclude.transclude(function(caseElement, selectedScope) {
28227                       selectedScopes.push(selectedScope);
28228                       var anchor = selectedTransclude.element;
28229                       caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
28230                       var block = { clone: caseElement };
28231
28232                       selectedElements.push(block);
28233                       $animate.enter(caseElement, anchor.parent(), anchor);
28234                     });
28235                   });
28236                 }
28237               });
28238             }
28239           };
28240         }];
28241
28242         var ngSwitchWhenDirective = ngDirective({
28243           transclude: 'element',
28244           priority: 1200,
28245           require: '^ngSwitch',
28246           multiElement: true,
28247           link: function(scope, element, attrs, ctrl, $transclude) {
28248             ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
28249             ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
28250           }
28251         });
28252
28253         var ngSwitchDefaultDirective = ngDirective({
28254           transclude: 'element',
28255           priority: 1200,
28256           require: '^ngSwitch',
28257           multiElement: true,
28258           link: function(scope, element, attr, ctrl, $transclude) {
28259             ctrl.cases['?'] = (ctrl.cases['?'] || []);
28260             ctrl.cases['?'].push({ transclude: $transclude, element: element });
28261            }
28262         });
28263
28264         /**
28265          * @ngdoc directive
28266          * @name ngTransclude
28267          * @restrict EAC
28268          *
28269          * @description
28270          * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
28271          *
28272          * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
28273          *
28274          * @element ANY
28275          *
28276          * @example
28277            <example module="transcludeExample">
28278              <file name="index.html">
28279                <script>
28280                  angular.module('transcludeExample', [])
28281                   .directive('pane', function(){
28282                      return {
28283                        restrict: 'E',
28284                        transclude: true,
28285                        scope: { title:'@' },
28286                        template: '<div style="border: 1px solid black;">' +
28287                                    '<div style="background-color: gray">{{title}}</div>' +
28288                                    '<ng-transclude></ng-transclude>' +
28289                                  '</div>'
28290                      };
28291                  })
28292                  .controller('ExampleController', ['$scope', function($scope) {
28293                    $scope.title = 'Lorem Ipsum';
28294                    $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
28295                  }]);
28296                </script>
28297                <div ng-controller="ExampleController">
28298                  <input ng-model="title" aria-label="title"> <br/>
28299                  <textarea ng-model="text" aria-label="text"></textarea> <br/>
28300                  <pane title="{{title}}">{{text}}</pane>
28301                </div>
28302              </file>
28303              <file name="protractor.js" type="protractor">
28304                 it('should have transcluded', function() {
28305                   var titleElement = element(by.model('title'));
28306                   titleElement.clear();
28307                   titleElement.sendKeys('TITLE');
28308                   var textElement = element(by.model('text'));
28309                   textElement.clear();
28310                   textElement.sendKeys('TEXT');
28311                   expect(element(by.binding('title')).getText()).toEqual('TITLE');
28312                   expect(element(by.binding('text')).getText()).toEqual('TEXT');
28313                 });
28314              </file>
28315            </example>
28316          *
28317          */
28318         var ngTranscludeDirective = ngDirective({
28319           restrict: 'EAC',
28320           link: function($scope, $element, $attrs, controller, $transclude) {
28321             if (!$transclude) {
28322               throw minErr('ngTransclude')('orphan',
28323                'Illegal use of ngTransclude directive in the template! ' +
28324                'No parent directive that requires a transclusion found. ' +
28325                'Element: {0}',
28326                startingTag($element));
28327             }
28328
28329             $transclude(function(clone) {
28330               $element.empty();
28331               $element.append(clone);
28332             });
28333           }
28334         });
28335
28336         /**
28337          * @ngdoc directive
28338          * @name script
28339          * @restrict E
28340          *
28341          * @description
28342          * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
28343          * template can be used by {@link ng.directive:ngInclude `ngInclude`},
28344          * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
28345          * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
28346          * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
28347          *
28348          * @param {string} type Must be set to `'text/ng-template'`.
28349          * @param {string} id Cache name of the template.
28350          *
28351          * @example
28352           <example>
28353             <file name="index.html">
28354               <script type="text/ng-template" id="/tpl.html">
28355                 Content of the template.
28356               </script>
28357
28358               <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
28359               <div id="tpl-content" ng-include src="currentTpl"></div>
28360             </file>
28361             <file name="protractor.js" type="protractor">
28362               it('should load template defined inside script tag', function() {
28363                 element(by.css('#tpl-link')).click();
28364                 expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
28365               });
28366             </file>
28367           </example>
28368          */
28369         var scriptDirective = ['$templateCache', function($templateCache) {
28370           return {
28371             restrict: 'E',
28372             terminal: true,
28373             compile: function(element, attr) {
28374               if (attr.type == 'text/ng-template') {
28375                 var templateUrl = attr.id,
28376                     text = element[0].text;
28377
28378                 $templateCache.put(templateUrl, text);
28379               }
28380             }
28381           };
28382         }];
28383
28384         var noopNgModelController = { $setViewValue: noop, $render: noop };
28385
28386         function chromeHack(optionElement) {
28387           // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
28388           // Adding an <option selected="selected"> element to a <select required="required"> should
28389           // automatically select the new element
28390           if (optionElement[0].hasAttribute('selected')) {
28391             optionElement[0].selected = true;
28392           }
28393         }
28394
28395         /**
28396          * @ngdoc type
28397          * @name  select.SelectController
28398          * @description
28399          * The controller for the `<select>` directive. This provides support for reading
28400          * and writing the selected value(s) of the control and also coordinates dynamically
28401          * added `<option>` elements, perhaps by an `ngRepeat` directive.
28402          */
28403         var SelectController =
28404                 ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
28405
28406           var self = this,
28407               optionsMap = new HashMap();
28408
28409           // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
28410           self.ngModelCtrl = noopNgModelController;
28411
28412           // The "unknown" option is one that is prepended to the list if the viewValue
28413           // does not match any of the options. When it is rendered the value of the unknown
28414           // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
28415           //
28416           // We can't just jqLite('<option>') since jqLite is not smart enough
28417           // to create it in <select> and IE barfs otherwise.
28418           self.unknownOption = jqLite(document.createElement('option'));
28419           self.renderUnknownOption = function(val) {
28420             var unknownVal = '? ' + hashKey(val) + ' ?';
28421             self.unknownOption.val(unknownVal);
28422             $element.prepend(self.unknownOption);
28423             $element.val(unknownVal);
28424           };
28425
28426           $scope.$on('$destroy', function() {
28427             // disable unknown option so that we don't do work when the whole select is being destroyed
28428             self.renderUnknownOption = noop;
28429           });
28430
28431           self.removeUnknownOption = function() {
28432             if (self.unknownOption.parent()) self.unknownOption.remove();
28433           };
28434
28435
28436           // Read the value of the select control, the implementation of this changes depending
28437           // upon whether the select can have multiple values and whether ngOptions is at work.
28438           self.readValue = function readSingleValue() {
28439             self.removeUnknownOption();
28440             return $element.val();
28441           };
28442
28443
28444           // Write the value to the select control, the implementation of this changes depending
28445           // upon whether the select can have multiple values and whether ngOptions is at work.
28446           self.writeValue = function writeSingleValue(value) {
28447             if (self.hasOption(value)) {
28448               self.removeUnknownOption();
28449               $element.val(value);
28450               if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
28451             } else {
28452               if (value == null && self.emptyOption) {
28453                 self.removeUnknownOption();
28454                 $element.val('');
28455               } else {
28456                 self.renderUnknownOption(value);
28457               }
28458             }
28459           };
28460
28461
28462           // Tell the select control that an option, with the given value, has been added
28463           self.addOption = function(value, element) {
28464             assertNotHasOwnProperty(value, '"option value"');
28465             if (value === '') {
28466               self.emptyOption = element;
28467             }
28468             var count = optionsMap.get(value) || 0;
28469             optionsMap.put(value, count + 1);
28470             self.ngModelCtrl.$render();
28471             chromeHack(element);
28472           };
28473
28474           // Tell the select control that an option, with the given value, has been removed
28475           self.removeOption = function(value) {
28476             var count = optionsMap.get(value);
28477             if (count) {
28478               if (count === 1) {
28479                 optionsMap.remove(value);
28480                 if (value === '') {
28481                   self.emptyOption = undefined;
28482                 }
28483               } else {
28484                 optionsMap.put(value, count - 1);
28485               }
28486             }
28487           };
28488
28489           // Check whether the select control has an option matching the given value
28490           self.hasOption = function(value) {
28491             return !!optionsMap.get(value);
28492           };
28493
28494
28495           self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
28496
28497             if (interpolateValueFn) {
28498               // The value attribute is interpolated
28499               var oldVal;
28500               optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
28501                 if (isDefined(oldVal)) {
28502                   self.removeOption(oldVal);
28503                 }
28504                 oldVal = newVal;
28505                 self.addOption(newVal, optionElement);
28506               });
28507             } else if (interpolateTextFn) {
28508               // The text content is interpolated
28509               optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
28510                 optionAttrs.$set('value', newVal);
28511                 if (oldVal !== newVal) {
28512                   self.removeOption(oldVal);
28513                 }
28514                 self.addOption(newVal, optionElement);
28515               });
28516             } else {
28517               // The value attribute is static
28518               self.addOption(optionAttrs.value, optionElement);
28519             }
28520
28521             optionElement.on('$destroy', function() {
28522               self.removeOption(optionAttrs.value);
28523               self.ngModelCtrl.$render();
28524             });
28525           };
28526         }];
28527
28528         /**
28529          * @ngdoc directive
28530          * @name select
28531          * @restrict E
28532          *
28533          * @description
28534          * HTML `SELECT` element with angular data-binding.
28535          *
28536          * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
28537          * between the scope and the `<select>` control (including setting default values).
28538          * Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
28539          * {@link ngOptions `ngOptions`} directives.
28540          *
28541          * When an item in the `<select>` menu is selected, the value of the selected option will be bound
28542          * to the model identified by the `ngModel` directive. With static or repeated options, this is
28543          * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
28544          * If you want dynamic value attributes, you can use interpolation inside the value attribute.
28545          *
28546          * <div class="alert alert-warning">
28547          * Note that the value of a `select` directive used without `ngOptions` is always a string.
28548          * When the model needs to be bound to a non-string value, you must either explictly convert it
28549          * using a directive (see example below) or use `ngOptions` to specify the set of options.
28550          * This is because an option element can only be bound to string values at present.
28551          * </div>
28552          *
28553          * If the viewValue of `ngModel` does not match any of the options, then the control
28554          * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
28555          *
28556          * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
28557          * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
28558          * option. See example below for demonstration.
28559          *
28560          * <div class="alert alert-info">
28561          * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
28562          * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
28563          * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
28564          * comprehension expression, and additionally in reducing memory and increasing speed by not creating
28565          * a new scope for each repeated instance.
28566          * </div>
28567          *
28568          *
28569          * @param {string} ngModel Assignable angular expression to data-bind to.
28570          * @param {string=} name Property name of the form under which the control is published.
28571          * @param {string=} multiple Allows multiple options to be selected. The selected values will be
28572          *     bound to the model as an array.
28573          * @param {string=} required Sets `required` validation error key if the value is not entered.
28574          * @param {string=} ngRequired Adds required attribute and required validation constraint to
28575          * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
28576          * when you want to data-bind to the required attribute.
28577          * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
28578          *    interaction with the select element.
28579          * @param {string=} ngOptions sets the options that the select is populated with and defines what is
28580          * set on the model on selection. See {@link ngOptions `ngOptions`}.
28581          *
28582          * @example
28583          * ### Simple `select` elements with static options
28584          *
28585          * <example name="static-select" module="staticSelect">
28586          * <file name="index.html">
28587          * <div ng-controller="ExampleController">
28588          *   <form name="myForm">
28589          *     <label for="singleSelect"> Single select: </label><br>
28590          *     <select name="singleSelect" ng-model="data.singleSelect">
28591          *       <option value="option-1">Option 1</option>
28592          *       <option value="option-2">Option 2</option>
28593          *     </select><br>
28594          *
28595          *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
28596          *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
28597          *       <option value="">---Please select---</option> <!-- not selected / blank option -->
28598          *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
28599          *       <option value="option-2">Option 2</option>
28600          *     </select><br>
28601          *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
28602          *     <tt>singleSelect = {{data.singleSelect}}</tt>
28603          *
28604          *     <hr>
28605          *     <label for="multipleSelect"> Multiple select: </label><br>
28606          *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
28607          *       <option value="option-1">Option 1</option>
28608          *       <option value="option-2">Option 2</option>
28609          *       <option value="option-3">Option 3</option>
28610          *     </select><br>
28611          *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
28612          *   </form>
28613          * </div>
28614          * </file>
28615          * <file name="app.js">
28616          *  angular.module('staticSelect', [])
28617          *    .controller('ExampleController', ['$scope', function($scope) {
28618          *      $scope.data = {
28619          *       singleSelect: null,
28620          *       multipleSelect: [],
28621          *       option1: 'option-1',
28622          *      };
28623          *
28624          *      $scope.forceUnknownOption = function() {
28625          *        $scope.data.singleSelect = 'nonsense';
28626          *      };
28627          *   }]);
28628          * </file>
28629          *</example>
28630          *
28631          * ### Using `ngRepeat` to generate `select` options
28632          * <example name="ngrepeat-select" module="ngrepeatSelect">
28633          * <file name="index.html">
28634          * <div ng-controller="ExampleController">
28635          *   <form name="myForm">
28636          *     <label for="repeatSelect"> Repeat select: </label>
28637          *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
28638          *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
28639          *     </select>
28640          *   </form>
28641          *   <hr>
28642          *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
28643          * </div>
28644          * </file>
28645          * <file name="app.js">
28646          *  angular.module('ngrepeatSelect', [])
28647          *    .controller('ExampleController', ['$scope', function($scope) {
28648          *      $scope.data = {
28649          *       repeatSelect: null,
28650          *       availableOptions: [
28651          *         {id: '1', name: 'Option A'},
28652          *         {id: '2', name: 'Option B'},
28653          *         {id: '3', name: 'Option C'}
28654          *       ],
28655          *      };
28656          *   }]);
28657          * </file>
28658          *</example>
28659          *
28660          *
28661          * ### Using `select` with `ngOptions` and setting a default value
28662          * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
28663          *
28664          * <example name="select-with-default-values" module="defaultValueSelect">
28665          * <file name="index.html">
28666          * <div ng-controller="ExampleController">
28667          *   <form name="myForm">
28668          *     <label for="mySelect">Make a choice:</label>
28669          *     <select name="mySelect" id="mySelect"
28670          *       ng-options="option.name for option in data.availableOptions track by option.id"
28671          *       ng-model="data.selectedOption"></select>
28672          *   </form>
28673          *   <hr>
28674          *   <tt>option = {{data.selectedOption}}</tt><br/>
28675          * </div>
28676          * </file>
28677          * <file name="app.js">
28678          *  angular.module('defaultValueSelect', [])
28679          *    .controller('ExampleController', ['$scope', function($scope) {
28680          *      $scope.data = {
28681          *       availableOptions: [
28682          *         {id: '1', name: 'Option A'},
28683          *         {id: '2', name: 'Option B'},
28684          *         {id: '3', name: 'Option C'}
28685          *       ],
28686          *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
28687          *       };
28688          *   }]);
28689          * </file>
28690          *</example>
28691          *
28692          *
28693          * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
28694          *
28695          * <example name="select-with-non-string-options" module="nonStringSelect">
28696          *   <file name="index.html">
28697          *     <select ng-model="model.id" convert-to-number>
28698          *       <option value="0">Zero</option>
28699          *       <option value="1">One</option>
28700          *       <option value="2">Two</option>
28701          *     </select>
28702          *     {{ model }}
28703          *   </file>
28704          *   <file name="app.js">
28705          *     angular.module('nonStringSelect', [])
28706          *       .run(function($rootScope) {
28707          *         $rootScope.model = { id: 2 };
28708          *       })
28709          *       .directive('convertToNumber', function() {
28710          *         return {
28711          *           require: 'ngModel',
28712          *           link: function(scope, element, attrs, ngModel) {
28713          *             ngModel.$parsers.push(function(val) {
28714          *               return parseInt(val, 10);
28715          *             });
28716          *             ngModel.$formatters.push(function(val) {
28717          *               return '' + val;
28718          *             });
28719          *           }
28720          *         };
28721          *       });
28722          *   </file>
28723          *   <file name="protractor.js" type="protractor">
28724          *     it('should initialize to model', function() {
28725          *       var select = element(by.css('select'));
28726          *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
28727          *     });
28728          *   </file>
28729          * </example>
28730          *
28731          */
28732         var selectDirective = function() {
28733
28734           return {
28735             restrict: 'E',
28736             require: ['select', '?ngModel'],
28737             controller: SelectController,
28738             priority: 1,
28739             link: {
28740               pre: selectPreLink
28741             }
28742           };
28743
28744           function selectPreLink(scope, element, attr, ctrls) {
28745
28746               // if ngModel is not defined, we don't need to do anything
28747               var ngModelCtrl = ctrls[1];
28748               if (!ngModelCtrl) return;
28749
28750               var selectCtrl = ctrls[0];
28751
28752               selectCtrl.ngModelCtrl = ngModelCtrl;
28753
28754               // We delegate rendering to the `writeValue` method, which can be changed
28755               // if the select can have multiple selected values or if the options are being
28756               // generated by `ngOptions`
28757               ngModelCtrl.$render = function() {
28758                 selectCtrl.writeValue(ngModelCtrl.$viewValue);
28759               };
28760
28761               // When the selected item(s) changes we delegate getting the value of the select control
28762               // to the `readValue` method, which can be changed if the select can have multiple
28763               // selected values or if the options are being generated by `ngOptions`
28764               element.on('change', function() {
28765                 scope.$apply(function() {
28766                   ngModelCtrl.$setViewValue(selectCtrl.readValue());
28767                 });
28768               });
28769
28770               // If the select allows multiple values then we need to modify how we read and write
28771               // values from and to the control; also what it means for the value to be empty and
28772               // we have to add an extra watch since ngModel doesn't work well with arrays - it
28773               // doesn't trigger rendering if only an item in the array changes.
28774               if (attr.multiple) {
28775
28776                 // Read value now needs to check each option to see if it is selected
28777                 selectCtrl.readValue = function readMultipleValue() {
28778                   var array = [];
28779                   forEach(element.find('option'), function(option) {
28780                     if (option.selected) {
28781                       array.push(option.value);
28782                     }
28783                   });
28784                   return array;
28785                 };
28786
28787                 // Write value now needs to set the selected property of each matching option
28788                 selectCtrl.writeValue = function writeMultipleValue(value) {
28789                   var items = new HashMap(value);
28790                   forEach(element.find('option'), function(option) {
28791                     option.selected = isDefined(items.get(option.value));
28792                   });
28793                 };
28794
28795                 // we have to do it on each watch since ngModel watches reference, but
28796                 // we need to work of an array, so we need to see if anything was inserted/removed
28797                 var lastView, lastViewRef = NaN;
28798                 scope.$watch(function selectMultipleWatch() {
28799                   if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
28800                     lastView = shallowCopy(ngModelCtrl.$viewValue);
28801                     ngModelCtrl.$render();
28802                   }
28803                   lastViewRef = ngModelCtrl.$viewValue;
28804                 });
28805
28806                 // If we are a multiple select then value is now a collection
28807                 // so the meaning of $isEmpty changes
28808                 ngModelCtrl.$isEmpty = function(value) {
28809                   return !value || value.length === 0;
28810                 };
28811
28812               }
28813             }
28814         };
28815
28816
28817         // The option directive is purely designed to communicate the existence (or lack of)
28818         // of dynamically created (and destroyed) option elements to their containing select
28819         // directive via its controller.
28820         var optionDirective = ['$interpolate', function($interpolate) {
28821           return {
28822             restrict: 'E',
28823             priority: 100,
28824             compile: function(element, attr) {
28825
28826               if (isDefined(attr.value)) {
28827                 // If the value attribute is defined, check if it contains an interpolation
28828                 var interpolateValueFn = $interpolate(attr.value, true);
28829               } else {
28830                 // If the value attribute is not defined then we fall back to the
28831                 // text content of the option element, which may be interpolated
28832                 var interpolateTextFn = $interpolate(element.text(), true);
28833                 if (!interpolateTextFn) {
28834                   attr.$set('value', element.text());
28835                 }
28836               }
28837
28838               return function(scope, element, attr) {
28839
28840                 // This is an optimization over using ^^ since we don't want to have to search
28841                 // all the way to the root of the DOM for every single option element
28842                 var selectCtrlName = '$selectController',
28843                     parent = element.parent(),
28844                     selectCtrl = parent.data(selectCtrlName) ||
28845                       parent.parent().data(selectCtrlName); // in case we are in optgroup
28846
28847                 if (selectCtrl) {
28848                   selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
28849                 }
28850               };
28851             }
28852           };
28853         }];
28854
28855         var styleDirective = valueFn({
28856           restrict: 'E',
28857           terminal: false
28858         });
28859
28860         var requiredDirective = function() {
28861           return {
28862             restrict: 'A',
28863             require: '?ngModel',
28864             link: function(scope, elm, attr, ctrl) {
28865               if (!ctrl) return;
28866               attr.required = true; // force truthy in case we are on non input element
28867
28868               ctrl.$validators.required = function(modelValue, viewValue) {
28869                 return !attr.required || !ctrl.$isEmpty(viewValue);
28870               };
28871
28872               attr.$observe('required', function() {
28873                 ctrl.$validate();
28874               });
28875             }
28876           };
28877         };
28878
28879
28880         var patternDirective = function() {
28881           return {
28882             restrict: 'A',
28883             require: '?ngModel',
28884             link: function(scope, elm, attr, ctrl) {
28885               if (!ctrl) return;
28886
28887               var regexp, patternExp = attr.ngPattern || attr.pattern;
28888               attr.$observe('pattern', function(regex) {
28889                 if (isString(regex) && regex.length > 0) {
28890                   regex = new RegExp('^' + regex + '$');
28891                 }
28892
28893                 if (regex && !regex.test) {
28894                   throw minErr('ngPattern')('noregexp',
28895                     'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
28896                     regex, startingTag(elm));
28897                 }
28898
28899                 regexp = regex || undefined;
28900                 ctrl.$validate();
28901               });
28902
28903               ctrl.$validators.pattern = function(modelValue, viewValue) {
28904                 // HTML5 pattern constraint validates the input value, so we validate the viewValue
28905                 return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
28906               };
28907             }
28908           };
28909         };
28910
28911
28912         var maxlengthDirective = function() {
28913           return {
28914             restrict: 'A',
28915             require: '?ngModel',
28916             link: function(scope, elm, attr, ctrl) {
28917               if (!ctrl) return;
28918
28919               var maxlength = -1;
28920               attr.$observe('maxlength', function(value) {
28921                 var intVal = toInt(value);
28922                 maxlength = isNaN(intVal) ? -1 : intVal;
28923                 ctrl.$validate();
28924               });
28925               ctrl.$validators.maxlength = function(modelValue, viewValue) {
28926                 return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
28927               };
28928             }
28929           };
28930         };
28931
28932         var minlengthDirective = function() {
28933           return {
28934             restrict: 'A',
28935             require: '?ngModel',
28936             link: function(scope, elm, attr, ctrl) {
28937               if (!ctrl) return;
28938
28939               var minlength = 0;
28940               attr.$observe('minlength', function(value) {
28941                 minlength = toInt(value) || 0;
28942                 ctrl.$validate();
28943               });
28944               ctrl.$validators.minlength = function(modelValue, viewValue) {
28945                 return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
28946               };
28947             }
28948           };
28949         };
28950
28951         if (window.angular.bootstrap) {
28952           //AngularJS is already loaded, so we can return here...
28953           console.log('WARNING: Tried to load angular more than once.');
28954           return;
28955         }
28956
28957         //try to bind to jquery now so that one can write jqLite(document).ready()
28958         //but we will rebind on bootstrap again.
28959         bindJQuery();
28960
28961         publishExternalAPI(angular);
28962
28963         angular.module("ngLocale", [], ["$provide", function($provide) {
28964         var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
28965         function getDecimals(n) {
28966           n = n + '';
28967           var i = n.indexOf('.');
28968           return (i == -1) ? 0 : n.length - i - 1;
28969         }
28970
28971         function getVF(n, opt_precision) {
28972           var v = opt_precision;
28973
28974           if (undefined === v) {
28975             v = Math.min(getDecimals(n), 3);
28976           }
28977
28978           var base = Math.pow(10, v);
28979           var f = ((n * base) | 0) % base;
28980           return {v: v, f: f};
28981         }
28982
28983         $provide.value("$locale", {
28984           "DATETIME_FORMATS": {
28985             "AMPMS": [
28986               "AM",
28987               "PM"
28988             ],
28989             "DAY": [
28990               "Sunday",
28991               "Monday",
28992               "Tuesday",
28993               "Wednesday",
28994               "Thursday",
28995               "Friday",
28996               "Saturday"
28997             ],
28998             "ERANAMES": [
28999               "Before Christ",
29000               "Anno Domini"
29001             ],
29002             "ERAS": [
29003               "BC",
29004               "AD"
29005             ],
29006             "FIRSTDAYOFWEEK": 6,
29007             "MONTH": [
29008               "January",
29009               "February",
29010               "March",
29011               "April",
29012               "May",
29013               "June",
29014               "July",
29015               "August",
29016               "September",
29017               "October",
29018               "November",
29019               "December"
29020             ],
29021             "SHORTDAY": [
29022               "Sun",
29023               "Mon",
29024               "Tue",
29025               "Wed",
29026               "Thu",
29027               "Fri",
29028               "Sat"
29029             ],
29030             "SHORTMONTH": [
29031               "Jan",
29032               "Feb",
29033               "Mar",
29034               "Apr",
29035               "May",
29036               "Jun",
29037               "Jul",
29038               "Aug",
29039               "Sep",
29040               "Oct",
29041               "Nov",
29042               "Dec"
29043             ],
29044             "WEEKENDRANGE": [
29045               5,
29046               6
29047             ],
29048             "fullDate": "EEEE, MMMM d, y",
29049             "longDate": "MMMM d, y",
29050             "medium": "MMM d, y h:mm:ss a",
29051             "mediumDate": "MMM d, y",
29052             "mediumTime": "h:mm:ss a",
29053             "short": "M/d/yy h:mm a",
29054             "shortDate": "M/d/yy",
29055             "shortTime": "h:mm a"
29056           },
29057           "NUMBER_FORMATS": {
29058             "CURRENCY_SYM": "$",
29059             "DECIMAL_SEP": ".",
29060             "GROUP_SEP": ",",
29061             "PATTERNS": [
29062               {
29063                 "gSize": 3,
29064                 "lgSize": 3,
29065                 "maxFrac": 3,
29066                 "minFrac": 0,
29067                 "minInt": 1,
29068                 "negPre": "-",
29069                 "negSuf": "",
29070                 "posPre": "",
29071                 "posSuf": ""
29072               },
29073               {
29074                 "gSize": 3,
29075                 "lgSize": 3,
29076                 "maxFrac": 2,
29077                 "minFrac": 2,
29078                 "minInt": 1,
29079                 "negPre": "-\u00a4",
29080                 "negSuf": "",
29081                 "posPre": "\u00a4",
29082                 "posSuf": ""
29083               }
29084             ]
29085           },
29086           "id": "en-us",
29087           "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;}
29088         });
29089         }]);
29090
29091           jqLite(document).ready(function() {
29092             angularInit(document, bootstrap);
29093           });
29094
29095         })(window, document);
29096
29097         !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>');
29098
29099 /***/ },
29100 /* 3 */
29101 /***/ function(module, exports) {
29102
29103         /**
29104          * State-based routing for AngularJS
29105          * @version v0.2.15
29106          * @link http://angular-ui.github.com/
29107          * @license MIT License, http://www.opensource.org/licenses/MIT
29108          */
29109
29110         /* commonjs package manager support (eg componentjs) */
29111         if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
29112           module.exports = 'ui.router';
29113         }
29114
29115         (function (window, angular, undefined) {
29116         /*jshint globalstrict:true*/
29117         /*global angular:false*/
29118         'use strict';
29119
29120         var isDefined = angular.isDefined,
29121             isFunction = angular.isFunction,
29122             isString = angular.isString,
29123             isObject = angular.isObject,
29124             isArray = angular.isArray,
29125             forEach = angular.forEach,
29126             extend = angular.extend,
29127             copy = angular.copy;
29128
29129         function inherit(parent, extra) {
29130           return extend(new (extend(function() {}, { prototype: parent }))(), extra);
29131         }
29132
29133         function merge(dst) {
29134           forEach(arguments, function(obj) {
29135             if (obj !== dst) {
29136               forEach(obj, function(value, key) {
29137                 if (!dst.hasOwnProperty(key)) dst[key] = value;
29138               });
29139             }
29140           });
29141           return dst;
29142         }
29143
29144         /**
29145          * Finds the common ancestor path between two states.
29146          *
29147          * @param {Object} first The first state.
29148          * @param {Object} second The second state.
29149          * @return {Array} Returns an array of state names in descending order, not including the root.
29150          */
29151         function ancestors(first, second) {
29152           var path = [];
29153
29154           for (var n in first.path) {
29155             if (first.path[n] !== second.path[n]) break;
29156             path.push(first.path[n]);
29157           }
29158           return path;
29159         }
29160
29161         /**
29162          * IE8-safe wrapper for `Object.keys()`.
29163          *
29164          * @param {Object} object A JavaScript object.
29165          * @return {Array} Returns the keys of the object as an array.
29166          */
29167         function objectKeys(object) {
29168           if (Object.keys) {
29169             return Object.keys(object);
29170           }
29171           var result = [];
29172
29173           forEach(object, function(val, key) {
29174             result.push(key);
29175           });
29176           return result;
29177         }
29178
29179         /**
29180          * IE8-safe wrapper for `Array.prototype.indexOf()`.
29181          *
29182          * @param {Array} array A JavaScript array.
29183          * @param {*} value A value to search the array for.
29184          * @return {Number} Returns the array index value of `value`, or `-1` if not present.
29185          */
29186         function indexOf(array, value) {
29187           if (Array.prototype.indexOf) {
29188             return array.indexOf(value, Number(arguments[2]) || 0);
29189           }
29190           var len = array.length >>> 0, from = Number(arguments[2]) || 0;
29191           from = (from < 0) ? Math.ceil(from) : Math.floor(from);
29192
29193           if (from < 0) from += len;
29194
29195           for (; from < len; from++) {
29196             if (from in array && array[from] === value) return from;
29197           }
29198           return -1;
29199         }
29200
29201         /**
29202          * Merges a set of parameters with all parameters inherited between the common parents of the
29203          * current state and a given destination state.
29204          *
29205          * @param {Object} currentParams The value of the current state parameters ($stateParams).
29206          * @param {Object} newParams The set of parameters which will be composited with inherited params.
29207          * @param {Object} $current Internal definition of object representing the current state.
29208          * @param {Object} $to Internal definition of object representing state to transition to.
29209          */
29210         function inheritParams(currentParams, newParams, $current, $to) {
29211           var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];
29212
29213           for (var i in parents) {
29214             if (!parents[i].params) continue;
29215             parentParams = objectKeys(parents[i].params);
29216             if (!parentParams.length) continue;
29217
29218             for (var j in parentParams) {
29219               if (indexOf(inheritList, parentParams[j]) >= 0) continue;
29220               inheritList.push(parentParams[j]);
29221               inherited[parentParams[j]] = currentParams[parentParams[j]];
29222             }
29223           }
29224           return extend({}, inherited, newParams);
29225         }
29226
29227         /**
29228          * Performs a non-strict comparison of the subset of two objects, defined by a list of keys.
29229          *
29230          * @param {Object} a The first object.
29231          * @param {Object} b The second object.
29232          * @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified,
29233          *                     it defaults to the list of keys in `a`.
29234          * @return {Boolean} Returns `true` if the keys match, otherwise `false`.
29235          */
29236         function equalForKeys(a, b, keys) {
29237           if (!keys) {
29238             keys = [];
29239             for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
29240           }
29241
29242           for (var i=0; i<keys.length; i++) {
29243             var k = keys[i];
29244             if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
29245           }
29246           return true;
29247         }
29248
29249         /**
29250          * Returns the subset of an object, based on a list of keys.
29251          *
29252          * @param {Array} keys
29253          * @param {Object} values
29254          * @return {Boolean} Returns a subset of `values`.
29255          */
29256         function filterByKeys(keys, values) {
29257           var filtered = {};
29258
29259           forEach(keys, function (name) {
29260             filtered[name] = values[name];
29261           });
29262           return filtered;
29263         }
29264
29265         // like _.indexBy
29266         // when you know that your index values will be unique, or you want last-one-in to win
29267         function indexBy(array, propName) {
29268           var result = {};
29269           forEach(array, function(item) {
29270             result[item[propName]] = item;
29271           });
29272           return result;
29273         }
29274
29275         // extracted from underscore.js
29276         // Return a copy of the object only containing the whitelisted properties.
29277         function pick(obj) {
29278           var copy = {};
29279           var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
29280           forEach(keys, function(key) {
29281             if (key in obj) copy[key] = obj[key];
29282           });
29283           return copy;
29284         }
29285
29286         // extracted from underscore.js
29287         // Return a copy of the object omitting the blacklisted properties.
29288         function omit(obj) {
29289           var copy = {};
29290           var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
29291           for (var key in obj) {
29292             if (indexOf(keys, key) == -1) copy[key] = obj[key];
29293           }
29294           return copy;
29295         }
29296
29297         function pluck(collection, key) {
29298           var result = isArray(collection) ? [] : {};
29299
29300           forEach(collection, function(val, i) {
29301             result[i] = isFunction(key) ? key(val) : val[key];
29302           });
29303           return result;
29304         }
29305
29306         function filter(collection, callback) {
29307           var array = isArray(collection);
29308           var result = array ? [] : {};
29309           forEach(collection, function(val, i) {
29310             if (callback(val, i)) {
29311               result[array ? result.length : i] = val;
29312             }
29313           });
29314           return result;
29315         }
29316
29317         function map(collection, callback) {
29318           var result = isArray(collection) ? [] : {};
29319
29320           forEach(collection, function(val, i) {
29321             result[i] = callback(val, i);
29322           });
29323           return result;
29324         }
29325
29326         /**
29327          * @ngdoc overview
29328          * @name ui.router.util
29329          *
29330          * @description
29331          * # ui.router.util sub-module
29332          *
29333          * This module is a dependency of other sub-modules. Do not include this module as a dependency
29334          * in your angular app (use {@link ui.router} module instead).
29335          *
29336          */
29337         angular.module('ui.router.util', ['ng']);
29338
29339         /**
29340          * @ngdoc overview
29341          * @name ui.router.router
29342          * 
29343          * @requires ui.router.util
29344          *
29345          * @description
29346          * # ui.router.router sub-module
29347          *
29348          * This module is a dependency of other sub-modules. Do not include this module as a dependency
29349          * in your angular app (use {@link ui.router} module instead).
29350          */
29351         angular.module('ui.router.router', ['ui.router.util']);
29352
29353         /**
29354          * @ngdoc overview
29355          * @name ui.router.state
29356          * 
29357          * @requires ui.router.router
29358          * @requires ui.router.util
29359          *
29360          * @description
29361          * # ui.router.state sub-module
29362          *
29363          * This module is a dependency of the main ui.router module. Do not include this module as a dependency
29364          * in your angular app (use {@link ui.router} module instead).
29365          * 
29366          */
29367         angular.module('ui.router.state', ['ui.router.router', 'ui.router.util']);
29368
29369         /**
29370          * @ngdoc overview
29371          * @name ui.router
29372          *
29373          * @requires ui.router.state
29374          *
29375          * @description
29376          * # ui.router
29377          * 
29378          * ## The main module for ui.router 
29379          * There are several sub-modules included with the ui.router module, however only this module is needed
29380          * as a dependency within your angular app. The other modules are for organization purposes. 
29381          *
29382          * The modules are:
29383          * * ui.router - the main "umbrella" module
29384          * * ui.router.router - 
29385          * 
29386          * *You'll need to include **only** this module as the dependency within your angular app.*
29387          * 
29388          * <pre>
29389          * <!doctype html>
29390          * <html ng-app="myApp">
29391          * <head>
29392          *   <script src="js/angular.js"></script>
29393          *   <!-- Include the ui-router script -->
29394          *   <script src="js/angular-ui-router.min.js"></script>
29395          *   <script>
29396          *     // ...and add 'ui.router' as a dependency
29397          *     var myApp = angular.module('myApp', ['ui.router']);
29398          *   </script>
29399          * </head>
29400          * <body>
29401          * </body>
29402          * </html>
29403          * </pre>
29404          */
29405         angular.module('ui.router', ['ui.router.state']);
29406
29407         angular.module('ui.router.compat', ['ui.router']);
29408
29409         /**
29410          * @ngdoc object
29411          * @name ui.router.util.$resolve
29412          *
29413          * @requires $q
29414          * @requires $injector
29415          *
29416          * @description
29417          * Manages resolution of (acyclic) graphs of promises.
29418          */
29419         $Resolve.$inject = ['$q', '$injector'];
29420         function $Resolve(  $q,    $injector) {
29421           
29422           var VISIT_IN_PROGRESS = 1,
29423               VISIT_DONE = 2,
29424               NOTHING = {},
29425               NO_DEPENDENCIES = [],
29426               NO_LOCALS = NOTHING,
29427               NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });
29428           
29429
29430           /**
29431            * @ngdoc function
29432            * @name ui.router.util.$resolve#study
29433            * @methodOf ui.router.util.$resolve
29434            *
29435            * @description
29436            * Studies a set of invocables that are likely to be used multiple times.
29437            * <pre>
29438            * $resolve.study(invocables)(locals, parent, self)
29439            * </pre>
29440            * is equivalent to
29441            * <pre>
29442            * $resolve.resolve(invocables, locals, parent, self)
29443            * </pre>
29444            * but the former is more efficient (in fact `resolve` just calls `study` 
29445            * internally).
29446            *
29447            * @param {object} invocables Invocable objects
29448            * @return {function} a function to pass in locals, parent and self
29449            */
29450           this.study = function (invocables) {
29451             if (!isObject(invocables)) throw new Error("'invocables' must be an object");
29452             var invocableKeys = objectKeys(invocables || {});
29453             
29454             // Perform a topological sort of invocables to build an ordered plan
29455             var plan = [], cycle = [], visited = {};
29456             function visit(value, key) {
29457               if (visited[key] === VISIT_DONE) return;
29458               
29459               cycle.push(key);
29460               if (visited[key] === VISIT_IN_PROGRESS) {
29461                 cycle.splice(0, indexOf(cycle, key));
29462                 throw new Error("Cyclic dependency: " + cycle.join(" -> "));
29463               }
29464               visited[key] = VISIT_IN_PROGRESS;
29465               
29466               if (isString(value)) {
29467                 plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
29468               } else {
29469                 var params = $injector.annotate(value);
29470                 forEach(params, function (param) {
29471                   if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);
29472                 });
29473                 plan.push(key, value, params);
29474               }
29475               
29476               cycle.pop();
29477               visited[key] = VISIT_DONE;
29478             }
29479             forEach(invocables, visit);
29480             invocables = cycle = visited = null; // plan is all that's required
29481             
29482             function isResolve(value) {
29483               return isObject(value) && value.then && value.$$promises;
29484             }
29485             
29486             return function (locals, parent, self) {
29487               if (isResolve(locals) && self === undefined) {
29488                 self = parent; parent = locals; locals = null;
29489               }
29490               if (!locals) locals = NO_LOCALS;
29491               else if (!isObject(locals)) {
29492                 throw new Error("'locals' must be an object");
29493               }       
29494               if (!parent) parent = NO_PARENT;
29495               else if (!isResolve(parent)) {
29496                 throw new Error("'parent' must be a promise returned by $resolve.resolve()");
29497               }
29498               
29499               // To complete the overall resolution, we have to wait for the parent
29500               // promise and for the promise for each invokable in our plan.
29501               var resolution = $q.defer(),
29502                   result = resolution.promise,
29503                   promises = result.$$promises = {},
29504                   values = extend({}, locals),
29505                   wait = 1 + plan.length/3,
29506                   merged = false;
29507                   
29508               function done() {
29509                 // Merge parent values we haven't got yet and publish our own $$values
29510                 if (!--wait) {
29511                   if (!merged) merge(values, parent.$$values); 
29512                   result.$$values = values;
29513                   result.$$promises = result.$$promises || true; // keep for isResolve()
29514                   delete result.$$inheritedValues;
29515                   resolution.resolve(values);
29516                 }
29517               }
29518               
29519               function fail(reason) {
29520                 result.$$failure = reason;
29521                 resolution.reject(reason);
29522               }
29523
29524               // Short-circuit if parent has already failed
29525               if (isDefined(parent.$$failure)) {
29526                 fail(parent.$$failure);
29527                 return result;
29528               }
29529               
29530               if (parent.$$inheritedValues) {
29531                 merge(values, omit(parent.$$inheritedValues, invocableKeys));
29532               }
29533
29534               // Merge parent values if the parent has already resolved, or merge
29535               // parent promises and wait if the parent resolve is still in progress.
29536               extend(promises, parent.$$promises);
29537               if (parent.$$values) {
29538                 merged = merge(values, omit(parent.$$values, invocableKeys));
29539                 result.$$inheritedValues = omit(parent.$$values, invocableKeys);
29540                 done();
29541               } else {
29542                 if (parent.$$inheritedValues) {
29543                   result.$$inheritedValues = omit(parent.$$inheritedValues, invocableKeys);
29544                 }        
29545                 parent.then(done, fail);
29546               }
29547               
29548               // Process each invocable in the plan, but ignore any where a local of the same name exists.
29549               for (var i=0, ii=plan.length; i<ii; i+=3) {
29550                 if (locals.hasOwnProperty(plan[i])) done();
29551                 else invoke(plan[i], plan[i+1], plan[i+2]);
29552               }
29553               
29554               function invoke(key, invocable, params) {
29555                 // Create a deferred for this invocation. Failures will propagate to the resolution as well.
29556                 var invocation = $q.defer(), waitParams = 0;
29557                 function onfailure(reason) {
29558                   invocation.reject(reason);
29559                   fail(reason);
29560                 }
29561                 // Wait for any parameter that we have a promise for (either from parent or from this
29562                 // resolve; in that case study() will have made sure it's ordered before us in the plan).
29563                 forEach(params, function (dep) {
29564                   if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) {
29565                     waitParams++;
29566                     promises[dep].then(function (result) {
29567                       values[dep] = result;
29568                       if (!(--waitParams)) proceed();
29569                     }, onfailure);
29570                   }
29571                 });
29572                 if (!waitParams) proceed();
29573                 function proceed() {
29574                   if (isDefined(result.$$failure)) return;
29575                   try {
29576                     invocation.resolve($injector.invoke(invocable, self, values));
29577                     invocation.promise.then(function (result) {
29578                       values[key] = result;
29579                       done();
29580                     }, onfailure);
29581                   } catch (e) {
29582                     onfailure(e);
29583                   }
29584                 }
29585                 // Publish promise synchronously; invocations further down in the plan may depend on it.
29586                 promises[key] = invocation.promise;
29587               }
29588               
29589               return result;
29590             };
29591           };
29592           
29593           /**
29594            * @ngdoc function
29595            * @name ui.router.util.$resolve#resolve
29596            * @methodOf ui.router.util.$resolve
29597            *
29598            * @description
29599            * Resolves a set of invocables. An invocable is a function to be invoked via 
29600            * `$injector.invoke()`, and can have an arbitrary number of dependencies. 
29601            * An invocable can either return a value directly,
29602            * or a `$q` promise. If a promise is returned it will be resolved and the 
29603            * resulting value will be used instead. Dependencies of invocables are resolved 
29604            * (in this order of precedence)
29605            *
29606            * - from the specified `locals`
29607            * - from another invocable that is part of this `$resolve` call
29608            * - from an invocable that is inherited from a `parent` call to `$resolve` 
29609            *   (or recursively
29610            * - from any ancestor `$resolve` of that parent).
29611            *
29612            * The return value of `$resolve` is a promise for an object that contains 
29613            * (in this order of precedence)
29614            *
29615            * - any `locals` (if specified)
29616            * - the resolved return values of all injectables
29617            * - any values inherited from a `parent` call to `$resolve` (if specified)
29618            *
29619            * The promise will resolve after the `parent` promise (if any) and all promises 
29620            * returned by injectables have been resolved. If any invocable 
29621            * (or `$injector.invoke`) throws an exception, or if a promise returned by an 
29622            * invocable is rejected, the `$resolve` promise is immediately rejected with the 
29623            * same error. A rejection of a `parent` promise (if specified) will likewise be 
29624            * propagated immediately. Once the `$resolve` promise has been rejected, no 
29625            * further invocables will be called.
29626            * 
29627            * Cyclic dependencies between invocables are not permitted and will caues `$resolve`
29628            * to throw an error. As a special case, an injectable can depend on a parameter 
29629            * with the same name as the injectable, which will be fulfilled from the `parent` 
29630            * injectable of the same name. This allows inherited values to be decorated. 
29631            * Note that in this case any other injectable in the same `$resolve` with the same
29632            * dependency would see the decorated value, not the inherited value.
29633            *
29634            * Note that missing dependencies -- unlike cyclic dependencies -- will cause an 
29635            * (asynchronous) rejection of the `$resolve` promise rather than a (synchronous) 
29636            * exception.
29637            *
29638            * Invocables are invoked eagerly as soon as all dependencies are available. 
29639            * This is true even for dependencies inherited from a `parent` call to `$resolve`.
29640            *
29641            * As a special case, an invocable can be a string, in which case it is taken to 
29642            * be a service name to be passed to `$injector.get()`. This is supported primarily 
29643            * for backwards-compatibility with the `resolve` property of `$routeProvider` 
29644            * routes.
29645            *
29646            * @param {object} invocables functions to invoke or 
29647            * `$injector` services to fetch.
29648            * @param {object} locals  values to make available to the injectables
29649            * @param {object} parent  a promise returned by another call to `$resolve`.
29650            * @param {object} self  the `this` for the invoked methods
29651            * @return {object} Promise for an object that contains the resolved return value
29652            * of all invocables, as well as any inherited and local values.
29653            */
29654           this.resolve = function (invocables, locals, parent, self) {
29655             return this.study(invocables)(locals, parent, self);
29656           };
29657         }
29658
29659         angular.module('ui.router.util').service('$resolve', $Resolve);
29660
29661
29662         /**
29663          * @ngdoc object
29664          * @name ui.router.util.$templateFactory
29665          *
29666          * @requires $http
29667          * @requires $templateCache
29668          * @requires $injector
29669          *
29670          * @description
29671          * Service. Manages loading of templates.
29672          */
29673         $TemplateFactory.$inject = ['$http', '$templateCache', '$injector'];
29674         function $TemplateFactory(  $http,   $templateCache,   $injector) {
29675
29676           /**
29677            * @ngdoc function
29678            * @name ui.router.util.$templateFactory#fromConfig
29679            * @methodOf ui.router.util.$templateFactory
29680            *
29681            * @description
29682            * Creates a template from a configuration object. 
29683            *
29684            * @param {object} config Configuration object for which to load a template. 
29685            * The following properties are search in the specified order, and the first one 
29686            * that is defined is used to create the template:
29687            *
29688            * @param {string|object} config.template html string template or function to 
29689            * load via {@link ui.router.util.$templateFactory#fromString fromString}.
29690            * @param {string|object} config.templateUrl url to load or a function returning 
29691            * the url to load via {@link ui.router.util.$templateFactory#fromUrl fromUrl}.
29692            * @param {Function} config.templateProvider function to invoke via 
29693            * {@link ui.router.util.$templateFactory#fromProvider fromProvider}.
29694            * @param {object} params  Parameters to pass to the template function.
29695            * @param {object} locals Locals to pass to `invoke` if the template is loaded 
29696            * via a `templateProvider`. Defaults to `{ params: params }`.
29697            *
29698            * @return {string|object}  The template html as a string, or a promise for 
29699            * that string,or `null` if no template is configured.
29700            */
29701           this.fromConfig = function (config, params, locals) {
29702             return (
29703               isDefined(config.template) ? this.fromString(config.template, params) :
29704               isDefined(config.templateUrl) ? this.fromUrl(config.templateUrl, params) :
29705               isDefined(config.templateProvider) ? this.fromProvider(config.templateProvider, params, locals) :
29706               null
29707             );
29708           };
29709
29710           /**
29711            * @ngdoc function
29712            * @name ui.router.util.$templateFactory#fromString
29713            * @methodOf ui.router.util.$templateFactory
29714            *
29715            * @description
29716            * Creates a template from a string or a function returning a string.
29717            *
29718            * @param {string|object} template html template as a string or function that 
29719            * returns an html template as a string.
29720            * @param {object} params Parameters to pass to the template function.
29721            *
29722            * @return {string|object} The template html as a string, or a promise for that 
29723            * string.
29724            */
29725           this.fromString = function (template, params) {
29726             return isFunction(template) ? template(params) : template;
29727           };
29728
29729           /**
29730            * @ngdoc function
29731            * @name ui.router.util.$templateFactory#fromUrl
29732            * @methodOf ui.router.util.$templateFactory
29733            * 
29734            * @description
29735            * Loads a template from the a URL via `$http` and `$templateCache`.
29736            *
29737            * @param {string|Function} url url of the template to load, or a function 
29738            * that returns a url.
29739            * @param {Object} params Parameters to pass to the url function.
29740            * @return {string|Promise.<string>} The template html as a string, or a promise 
29741            * for that string.
29742            */
29743           this.fromUrl = function (url, params) {
29744             if (isFunction(url)) url = url(params);
29745             if (url == null) return null;
29746             else return $http
29747                 .get(url, { cache: $templateCache, headers: { Accept: 'text/html' }})
29748                 .then(function(response) { return response.data; });
29749           };
29750
29751           /**
29752            * @ngdoc function
29753            * @name ui.router.util.$templateFactory#fromProvider
29754            * @methodOf ui.router.util.$templateFactory
29755            *
29756            * @description
29757            * Creates a template by invoking an injectable provider function.
29758            *
29759            * @param {Function} provider Function to invoke via `$injector.invoke`
29760            * @param {Object} params Parameters for the template.
29761            * @param {Object} locals Locals to pass to `invoke`. Defaults to 
29762            * `{ params: params }`.
29763            * @return {string|Promise.<string>} The template html as a string, or a promise 
29764            * for that string.
29765            */
29766           this.fromProvider = function (provider, params, locals) {
29767             return $injector.invoke(provider, null, locals || { params: params });
29768           };
29769         }
29770
29771         angular.module('ui.router.util').service('$templateFactory', $TemplateFactory);
29772
29773         var $$UMFP; // reference to $UrlMatcherFactoryProvider
29774
29775         /**
29776          * @ngdoc object
29777          * @name ui.router.util.type:UrlMatcher
29778          *
29779          * @description
29780          * Matches URLs against patterns and extracts named parameters from the path or the search
29781          * part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list
29782          * of search parameters. Multiple search parameter names are separated by '&'. Search parameters
29783          * do not influence whether or not a URL is matched, but their values are passed through into
29784          * the matched parameters returned by {@link ui.router.util.type:UrlMatcher#methods_exec exec}.
29785          *
29786          * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
29787          * syntax, which optionally allows a regular expression for the parameter to be specified:
29788          *
29789          * * `':'` name - colon placeholder
29790          * * `'*'` name - catch-all placeholder
29791          * * `'{' name '}'` - curly placeholder
29792          * * `'{' name ':' regexp|type '}'` - curly placeholder with regexp or type name. Should the
29793          *   regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash.
29794          *
29795          * Parameter names may contain only word characters (latin letters, digits, and underscore) and
29796          * must be unique within the pattern (across both path and search parameters). For colon
29797          * placeholders or curly placeholders without an explicit regexp, a path parameter matches any
29798          * number of characters other than '/'. For catch-all placeholders the path parameter matches
29799          * any number of characters.
29800          *
29801          * Examples:
29802          *
29803          * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for
29804          *   trailing slashes, and patterns have to match the entire path, not just a prefix.
29805          * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
29806          *   '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
29807          * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax.
29808          * * `'/user/{id:[^/]*}'` - Same as the previous example.
29809          * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id
29810          *   parameter consists of 1 to 8 hex digits.
29811          * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the
29812          *   path into the parameter 'path'.
29813          * * `'/files/*path'` - ditto.
29814          * * `'/calendar/{start:date}'` - Matches "/calendar/2014-11-12" (because the pattern defined
29815          *   in the built-in  `date` Type matches `2014-11-12`) and provides a Date object in $stateParams.start
29816          *
29817          * @param {string} pattern  The pattern to compile into a matcher.
29818          * @param {Object} config  A configuration object hash:
29819          * @param {Object=} parentMatcher Used to concatenate the pattern/config onto
29820          *   an existing UrlMatcher
29821          *
29822          * * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.
29823          * * `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`.
29824          *
29825          * @property {string} prefix  A static prefix of this pattern. The matcher guarantees that any
29826          *   URL matching this matcher (i.e. any string for which {@link ui.router.util.type:UrlMatcher#methods_exec exec()} returns
29827          *   non-null) will start with this prefix.
29828          *
29829          * @property {string} source  The pattern that was passed into the constructor
29830          *
29831          * @property {string} sourcePath  The path portion of the source property
29832          *
29833          * @property {string} sourceSearch  The search portion of the source property
29834          *
29835          * @property {string} regex  The constructed regex that will be used to match against the url when
29836          *   it is time to determine which url will match.
29837          *
29838          * @returns {Object}  New `UrlMatcher` object
29839          */
29840         function UrlMatcher(pattern, config, parentMatcher) {
29841           config = extend({ params: {} }, isObject(config) ? config : {});
29842
29843           // Find all placeholders and create a compiled pattern, using either classic or curly syntax:
29844           //   '*' name
29845           //   ':' name
29846           //   '{' name '}'
29847           //   '{' name ':' regexp '}'
29848           // The regular expression is somewhat complicated due to the need to allow curly braces
29849           // inside the regular expression. The placeholder regexp breaks down as follows:
29850           //    ([:*])([\w\[\]]+)              - classic placeholder ($1 / $2) (search version has - for snake-case)
29851           //    \{([\w\[\]]+)(?:\:( ... ))?\}  - curly brace placeholder ($3) with optional regexp/type ... ($4) (search version has - for snake-case
29852           //    (?: ... | ... | ... )+         - the regexp consists of any number of atoms, an atom being either
29853           //    [^{}\\]+                       - anything other than curly braces or backslash
29854           //    \\.                            - a backslash escape
29855           //    \{(?:[^{}\\]+|\\.)*\}          - a matched set of curly braces containing other atoms
29856           var placeholder       = /([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
29857               searchPlaceholder = /([:]?)([\w\[\]-]+)|\{([\w\[\]-]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
29858               compiled = '^', last = 0, m,
29859               segments = this.segments = [],
29860               parentParams = parentMatcher ? parentMatcher.params : {},
29861               params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet(),
29862               paramNames = [];
29863
29864           function addParameter(id, type, config, location) {
29865             paramNames.push(id);
29866             if (parentParams[id]) return parentParams[id];
29867             if (!/^\w+(-+\w+)*(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
29868             if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
29869             params[id] = new $$UMFP.Param(id, type, config, location);
29870             return params[id];
29871           }
29872
29873           function quoteRegExp(string, pattern, squash, optional) {
29874             var surroundPattern = ['',''], result = string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
29875             if (!pattern) return result;
29876             switch(squash) {
29877               case false: surroundPattern = ['(', ')' + (optional ? "?" : "")]; break;
29878               case true:  surroundPattern = ['?(', ')?']; break;
29879               default:    surroundPattern = ['(' + squash + "|", ')?']; break;
29880             }
29881             return result + surroundPattern[0] + pattern + surroundPattern[1];
29882           }
29883
29884           this.source = pattern;
29885
29886           // Split into static segments separated by path parameter placeholders.
29887           // The number of segments is always 1 more than the number of parameters.
29888           function matchDetails(m, isSearch) {
29889             var id, regexp, segment, type, cfg, arrayMode;
29890             id          = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
29891             cfg         = config.params[id];
29892             segment     = pattern.substring(last, m.index);
29893             regexp      = isSearch ? m[4] : m[4] || (m[1] == '*' ? '.*' : null);
29894             type        = $$UMFP.type(regexp || "string") || inherit($$UMFP.type("string"), { pattern: new RegExp(regexp, config.caseInsensitive ? 'i' : undefined) });
29895             return {
29896               id: id, regexp: regexp, segment: segment, type: type, cfg: cfg
29897             };
29898           }
29899
29900           var p, param, segment;
29901           while ((m = placeholder.exec(pattern))) {
29902             p = matchDetails(m, false);
29903             if (p.segment.indexOf('?') >= 0) break; // we're into the search part
29904
29905             param = addParameter(p.id, p.type, p.cfg, "path");
29906             compiled += quoteRegExp(p.segment, param.type.pattern.source, param.squash, param.isOptional);
29907             segments.push(p.segment);
29908             last = placeholder.lastIndex;
29909           }
29910           segment = pattern.substring(last);
29911
29912           // Find any search parameter names and remove them from the last segment
29913           var i = segment.indexOf('?');
29914
29915           if (i >= 0) {
29916             var search = this.sourceSearch = segment.substring(i);
29917             segment = segment.substring(0, i);
29918             this.sourcePath = pattern.substring(0, last + i);
29919
29920             if (search.length > 0) {
29921               last = 0;
29922               while ((m = searchPlaceholder.exec(search))) {
29923                 p = matchDetails(m, true);
29924                 param = addParameter(p.id, p.type, p.cfg, "search");
29925                 last = placeholder.lastIndex;
29926                 // check if ?&
29927               }
29928             }
29929           } else {
29930             this.sourcePath = pattern;
29931             this.sourceSearch = '';
29932           }
29933
29934           compiled += quoteRegExp(segment) + (config.strict === false ? '\/?' : '') + '$';
29935           segments.push(segment);
29936
29937           this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined);
29938           this.prefix = segments[0];
29939           this.$$paramNames = paramNames;
29940         }
29941
29942         /**
29943          * @ngdoc function
29944          * @name ui.router.util.type:UrlMatcher#concat
29945          * @methodOf ui.router.util.type:UrlMatcher
29946          *
29947          * @description
29948          * Returns a new matcher for a pattern constructed by appending the path part and adding the
29949          * search parameters of the specified pattern to this pattern. The current pattern is not
29950          * modified. This can be understood as creating a pattern for URLs that are relative to (or
29951          * suffixes of) the current pattern.
29952          *
29953          * @example
29954          * The following two matchers are equivalent:
29955          * <pre>
29956          * new UrlMatcher('/user/{id}?q').concat('/details?date');
29957          * new UrlMatcher('/user/{id}/details?q&date');
29958          * </pre>
29959          *
29960          * @param {string} pattern  The pattern to append.
29961          * @param {Object} config  An object hash of the configuration for the matcher.
29962          * @returns {UrlMatcher}  A matcher for the concatenated pattern.
29963          */
29964         UrlMatcher.prototype.concat = function (pattern, config) {
29965           // Because order of search parameters is irrelevant, we can add our own search
29966           // parameters to the end of the new pattern. Parse the new pattern by itself
29967           // and then join the bits together, but it's much easier to do this on a string level.
29968           var defaultConfig = {
29969             caseInsensitive: $$UMFP.caseInsensitive(),
29970             strict: $$UMFP.strictMode(),
29971             squash: $$UMFP.defaultSquashPolicy()
29972           };
29973           return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, extend(defaultConfig, config), this);
29974         };
29975
29976         UrlMatcher.prototype.toString = function () {
29977           return this.source;
29978         };
29979
29980         /**
29981          * @ngdoc function
29982          * @name ui.router.util.type:UrlMatcher#exec
29983          * @methodOf ui.router.util.type:UrlMatcher
29984          *
29985          * @description
29986          * Tests the specified path against this matcher, and returns an object containing the captured
29987          * parameter values, or null if the path does not match. The returned object contains the values
29988          * of any search parameters that are mentioned in the pattern, but their value may be null if
29989          * they are not present in `searchParams`. This means that search parameters are always treated
29990          * as optional.
29991          *
29992          * @example
29993          * <pre>
29994          * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', {
29995          *   x: '1', q: 'hello'
29996          * });
29997          * // returns { id: 'bob', q: 'hello', r: null }
29998          * </pre>
29999          *
30000          * @param {string} path  The URL path to match, e.g. `$location.path()`.
30001          * @param {Object} searchParams  URL search parameters, e.g. `$location.search()`.
30002          * @returns {Object}  The captured parameter values.
30003          */
30004         UrlMatcher.prototype.exec = function (path, searchParams) {
30005           var m = this.regexp.exec(path);
30006           if (!m) return null;
30007           searchParams = searchParams || {};
30008
30009           var paramNames = this.parameters(), nTotal = paramNames.length,
30010             nPath = this.segments.length - 1,
30011             values = {}, i, j, cfg, paramName;
30012
30013           if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'");
30014
30015           function decodePathArray(string) {
30016             function reverseString(str) { return str.split("").reverse().join(""); }
30017             function unquoteDashes(str) { return str.replace(/\\-/g, "-"); }
30018
30019             var split = reverseString(string).split(/-(?!\\)/);
30020             var allReversed = map(split, reverseString);
30021             return map(allReversed, unquoteDashes).reverse();
30022           }
30023
30024           for (i = 0; i < nPath; i++) {
30025             paramName = paramNames[i];
30026             var param = this.params[paramName];
30027             var paramVal = m[i+1];
30028             // if the param value matches a pre-replace pair, replace the value before decoding.
30029             for (j = 0; j < param.replace; j++) {
30030               if (param.replace[j].from === paramVal) paramVal = param.replace[j].to;
30031             }
30032             if (paramVal && param.array === true) paramVal = decodePathArray(paramVal);
30033             values[paramName] = param.value(paramVal);
30034           }
30035           for (/**/; i < nTotal; i++) {
30036             paramName = paramNames[i];
30037             values[paramName] = this.params[paramName].value(searchParams[paramName]);
30038           }
30039
30040           return values;
30041         };
30042
30043         /**
30044          * @ngdoc function
30045          * @name ui.router.util.type:UrlMatcher#parameters
30046          * @methodOf ui.router.util.type:UrlMatcher
30047          *
30048          * @description
30049          * Returns the names of all path and search parameters of this pattern in an unspecified order.
30050          *
30051          * @returns {Array.<string>}  An array of parameter names. Must be treated as read-only. If the
30052          *    pattern has no parameters, an empty array is returned.
30053          */
30054         UrlMatcher.prototype.parameters = function (param) {
30055           if (!isDefined(param)) return this.$$paramNames;
30056           return this.params[param] || null;
30057         };
30058
30059         /**
30060          * @ngdoc function
30061          * @name ui.router.util.type:UrlMatcher#validate
30062          * @methodOf ui.router.util.type:UrlMatcher
30063          *
30064          * @description
30065          * Checks an object hash of parameters to validate their correctness according to the parameter
30066          * types of this `UrlMatcher`.
30067          *
30068          * @param {Object} params The object hash of parameters to validate.
30069          * @returns {boolean} Returns `true` if `params` validates, otherwise `false`.
30070          */
30071         UrlMatcher.prototype.validates = function (params) {
30072           return this.params.$$validates(params);
30073         };
30074
30075         /**
30076          * @ngdoc function
30077          * @name ui.router.util.type:UrlMatcher#format
30078          * @methodOf ui.router.util.type:UrlMatcher
30079          *
30080          * @description
30081          * Creates a URL that matches this pattern by substituting the specified values
30082          * for the path and search parameters. Null values for path parameters are
30083          * treated as empty strings.
30084          *
30085          * @example
30086          * <pre>
30087          * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
30088          * // returns '/user/bob?q=yes'
30089          * </pre>
30090          *
30091          * @param {Object} values  the values to substitute for the parameters in this pattern.
30092          * @returns {string}  the formatted URL (path and optionally search part).
30093          */
30094         UrlMatcher.prototype.format = function (values) {
30095           values = values || {};
30096           var segments = this.segments, params = this.parameters(), paramset = this.params;
30097           if (!this.validates(values)) return null;
30098
30099           var i, search = false, nPath = segments.length - 1, nTotal = params.length, result = segments[0];
30100
30101           function encodeDashes(str) { // Replace dashes with encoded "\-"
30102             return encodeURIComponent(str).replace(/-/g, function(c) { return '%5C%' + c.charCodeAt(0).toString(16).toUpperCase(); });
30103           }
30104
30105           for (i = 0; i < nTotal; i++) {
30106             var isPathParam = i < nPath;
30107             var name = params[i], param = paramset[name], value = param.value(values[name]);
30108             var isDefaultValue = param.isOptional && param.type.equals(param.value(), value);
30109             var squash = isDefaultValue ? param.squash : false;
30110             var encoded = param.type.encode(value);
30111
30112             if (isPathParam) {
30113               var nextSegment = segments[i + 1];
30114               if (squash === false) {
30115                 if (encoded != null) {
30116                   if (isArray(encoded)) {
30117                     result += map(encoded, encodeDashes).join("-");
30118                   } else {
30119                     result += encodeURIComponent(encoded);
30120                   }
30121                 }
30122                 result += nextSegment;
30123               } else if (squash === true) {
30124                 var capture = result.match(/\/$/) ? /\/?(.*)/ : /(.*)/;
30125                 result += nextSegment.match(capture)[1];
30126               } else if (isString(squash)) {
30127                 result += squash + nextSegment;
30128               }
30129             } else {
30130               if (encoded == null || (isDefaultValue && squash !== false)) continue;
30131               if (!isArray(encoded)) encoded = [ encoded ];
30132               encoded = map(encoded, encodeURIComponent).join('&' + name + '=');
30133               result += (search ? '&' : '?') + (name + '=' + encoded);
30134               search = true;
30135             }
30136           }
30137
30138           return result;
30139         };
30140
30141         /**
30142          * @ngdoc object
30143          * @name ui.router.util.type:Type
30144          *
30145          * @description
30146          * Implements an interface to define custom parameter types that can be decoded from and encoded to
30147          * string parameters matched in a URL. Used by {@link ui.router.util.type:UrlMatcher `UrlMatcher`}
30148          * objects when matching or formatting URLs, or comparing or validating parameter values.
30149          *
30150          * See {@link ui.router.util.$urlMatcherFactory#methods_type `$urlMatcherFactory#type()`} for more
30151          * information on registering custom types.
30152          *
30153          * @param {Object} config  A configuration object which contains the custom type definition.  The object's
30154          *        properties will override the default methods and/or pattern in `Type`'s public interface.
30155          * @example
30156          * <pre>
30157          * {
30158          *   decode: function(val) { return parseInt(val, 10); },
30159          *   encode: function(val) { return val && val.toString(); },
30160          *   equals: function(a, b) { return this.is(a) && a === b; },
30161          *   is: function(val) { return angular.isNumber(val) isFinite(val) && val % 1 === 0; },
30162          *   pattern: /\d+/
30163          * }
30164          * </pre>
30165          *
30166          * @property {RegExp} pattern The regular expression pattern used to match values of this type when
30167          *           coming from a substring of a URL.
30168          *
30169          * @returns {Object}  Returns a new `Type` object.
30170          */
30171         function Type(config) {
30172           extend(this, config);
30173         }
30174
30175         /**
30176          * @ngdoc function
30177          * @name ui.router.util.type:Type#is
30178          * @methodOf ui.router.util.type:Type
30179          *
30180          * @description
30181          * Detects whether a value is of a particular type. Accepts a native (decoded) value
30182          * and determines whether it matches the current `Type` object.
30183          *
30184          * @param {*} val  The value to check.
30185          * @param {string} key  Optional. If the type check is happening in the context of a specific
30186          *        {@link ui.router.util.type:UrlMatcher `UrlMatcher`} object, this is the name of the
30187          *        parameter in which `val` is stored. Can be used for meta-programming of `Type` objects.
30188          * @returns {Boolean}  Returns `true` if the value matches the type, otherwise `false`.
30189          */
30190         Type.prototype.is = function(val, key) {
30191           return true;
30192         };
30193
30194         /**
30195          * @ngdoc function
30196          * @name ui.router.util.type:Type#encode
30197          * @methodOf ui.router.util.type:Type
30198          *
30199          * @description
30200          * Encodes a custom/native type value to a string that can be embedded in a URL. Note that the
30201          * return value does *not* need to be URL-safe (i.e. passed through `encodeURIComponent()`), it
30202          * only needs to be a representation of `val` that has been coerced to a string.
30203          *
30204          * @param {*} val  The value to encode.
30205          * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
30206          *        meta-programming of `Type` objects.
30207          * @returns {string}  Returns a string representation of `val` that can be encoded in a URL.
30208          */
30209         Type.prototype.encode = function(val, key) {
30210           return val;
30211         };
30212
30213         /**
30214          * @ngdoc function
30215          * @name ui.router.util.type:Type#decode
30216          * @methodOf ui.router.util.type:Type
30217          *
30218          * @description
30219          * Converts a parameter value (from URL string or transition param) to a custom/native value.
30220          *
30221          * @param {string} val  The URL parameter value to decode.
30222          * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
30223          *        meta-programming of `Type` objects.
30224          * @returns {*}  Returns a custom representation of the URL parameter value.
30225          */
30226         Type.prototype.decode = function(val, key) {
30227           return val;
30228         };
30229
30230         /**
30231          * @ngdoc function
30232          * @name ui.router.util.type:Type#equals
30233          * @methodOf ui.router.util.type:Type
30234          *
30235          * @description
30236          * Determines whether two decoded values are equivalent.
30237          *
30238          * @param {*} a  A value to compare against.
30239          * @param {*} b  A value to compare against.
30240          * @returns {Boolean}  Returns `true` if the values are equivalent/equal, otherwise `false`.
30241          */
30242         Type.prototype.equals = function(a, b) {
30243           return a == b;
30244         };
30245
30246         Type.prototype.$subPattern = function() {
30247           var sub = this.pattern.toString();
30248           return sub.substr(1, sub.length - 2);
30249         };
30250
30251         Type.prototype.pattern = /.*/;
30252
30253         Type.prototype.toString = function() { return "{Type:" + this.name + "}"; };
30254
30255         /** Given an encoded string, or a decoded object, returns a decoded object */
30256         Type.prototype.$normalize = function(val) {
30257           return this.is(val) ? val : this.decode(val);
30258         };
30259
30260         /*
30261          * Wraps an existing custom Type as an array of Type, depending on 'mode'.
30262          * e.g.:
30263          * - urlmatcher pattern "/path?{queryParam[]:int}"
30264          * - url: "/path?queryParam=1&queryParam=2
30265          * - $stateParams.queryParam will be [1, 2]
30266          * if `mode` is "auto", then
30267          * - url: "/path?queryParam=1 will create $stateParams.queryParam: 1
30268          * - url: "/path?queryParam=1&queryParam=2 will create $stateParams.queryParam: [1, 2]
30269          */
30270         Type.prototype.$asArray = function(mode, isSearch) {
30271           if (!mode) return this;
30272           if (mode === "auto" && !isSearch) throw new Error("'auto' array mode is for query parameters only");
30273
30274           function ArrayType(type, mode) {
30275             function bindTo(type, callbackName) {
30276               return function() {
30277                 return type[callbackName].apply(type, arguments);
30278               };
30279             }
30280
30281             // Wrap non-array value as array
30282             function arrayWrap(val) { return isArray(val) ? val : (isDefined(val) ? [ val ] : []); }
30283             // Unwrap array value for "auto" mode. Return undefined for empty array.
30284             function arrayUnwrap(val) {
30285               switch(val.length) {
30286                 case 0: return undefined;
30287                 case 1: return mode === "auto" ? val[0] : val;
30288                 default: return val;
30289               }
30290             }
30291             function falsey(val) { return !val; }
30292
30293             // Wraps type (.is/.encode/.decode) functions to operate on each value of an array
30294             function arrayHandler(callback, allTruthyMode) {
30295               return function handleArray(val) {
30296                 val = arrayWrap(val);
30297                 var result = map(val, callback);
30298                 if (allTruthyMode === true)
30299                   return filter(result, falsey).length === 0;
30300                 return arrayUnwrap(result);
30301               };
30302             }
30303
30304             // Wraps type (.equals) functions to operate on each value of an array
30305             function arrayEqualsHandler(callback) {
30306               return function handleArray(val1, val2) {
30307                 var left = arrayWrap(val1), right = arrayWrap(val2);
30308                 if (left.length !== right.length) return false;
30309                 for (var i = 0; i < left.length; i++) {
30310                   if (!callback(left[i], right[i])) return false;
30311                 }
30312                 return true;
30313               };
30314             }
30315
30316             this.encode = arrayHandler(bindTo(type, 'encode'));
30317             this.decode = arrayHandler(bindTo(type, 'decode'));
30318             this.is     = arrayHandler(bindTo(type, 'is'), true);
30319             this.equals = arrayEqualsHandler(bindTo(type, 'equals'));
30320             this.pattern = type.pattern;
30321             this.$normalize = arrayHandler(bindTo(type, '$normalize'));
30322             this.name = type.name;
30323             this.$arrayMode = mode;
30324           }
30325
30326           return new ArrayType(this, mode);
30327         };
30328
30329
30330
30331         /**
30332          * @ngdoc object
30333          * @name ui.router.util.$urlMatcherFactory
30334          *
30335          * @description
30336          * Factory for {@link ui.router.util.type:UrlMatcher `UrlMatcher`} instances. The factory
30337          * is also available to providers under the name `$urlMatcherFactoryProvider`.
30338          */
30339         function $UrlMatcherFactory() {
30340           $$UMFP = this;
30341
30342           var isCaseInsensitive = false, isStrictMode = true, defaultSquashPolicy = false;
30343
30344           function valToString(val) { return val != null ? val.toString().replace(/\//g, "%2F") : val; }
30345           function valFromString(val) { return val != null ? val.toString().replace(/%2F/g, "/") : val; }
30346
30347           var $types = {}, enqueue = true, typeQueue = [], injector, defaultTypes = {
30348             string: {
30349               encode: valToString,
30350               decode: valFromString,
30351               // TODO: in 1.0, make string .is() return false if value is undefined/null by default.
30352               // In 0.2.x, string params are optional by default for backwards compat
30353               is: function(val) { return val == null || !isDefined(val) || typeof val === "string"; },
30354               pattern: /[^/]*/
30355             },
30356             int: {
30357               encode: valToString,
30358               decode: function(val) { return parseInt(val, 10); },
30359               is: function(val) { return isDefined(val) && this.decode(val.toString()) === val; },
30360               pattern: /\d+/
30361             },
30362             bool: {
30363               encode: function(val) { return val ? 1 : 0; },
30364               decode: function(val) { return parseInt(val, 10) !== 0; },
30365               is: function(val) { return val === true || val === false; },
30366               pattern: /0|1/
30367             },
30368             date: {
30369               encode: function (val) {
30370                 if (!this.is(val))
30371                   return undefined;
30372                 return [ val.getFullYear(),
30373                   ('0' + (val.getMonth() + 1)).slice(-2),
30374                   ('0' + val.getDate()).slice(-2)
30375                 ].join("-");
30376               },
30377               decode: function (val) {
30378                 if (this.is(val)) return val;
30379                 var match = this.capture.exec(val);
30380                 return match ? new Date(match[1], match[2] - 1, match[3]) : undefined;
30381               },
30382               is: function(val) { return val instanceof Date && !isNaN(val.valueOf()); },
30383               equals: function (a, b) { return this.is(a) && this.is(b) && a.toISOString() === b.toISOString(); },
30384               pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/,
30385               capture: /([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/
30386             },
30387             json: {
30388               encode: angular.toJson,
30389               decode: angular.fromJson,
30390               is: angular.isObject,
30391               equals: angular.equals,
30392               pattern: /[^/]*/
30393             },
30394             any: { // does not encode/decode
30395               encode: angular.identity,
30396               decode: angular.identity,
30397               equals: angular.equals,
30398               pattern: /.*/
30399             }
30400           };
30401
30402           function getDefaultConfig() {
30403             return {
30404               strict: isStrictMode,
30405               caseInsensitive: isCaseInsensitive
30406             };
30407           }
30408
30409           function isInjectable(value) {
30410             return (isFunction(value) || (isArray(value) && isFunction(value[value.length - 1])));
30411           }
30412
30413           /**
30414            * [Internal] Get the default value of a parameter, which may be an injectable function.
30415            */
30416           $UrlMatcherFactory.$$getDefaultValue = function(config) {
30417             if (!isInjectable(config.value)) return config.value;
30418             if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
30419             return injector.invoke(config.value);
30420           };
30421
30422           /**
30423            * @ngdoc function
30424            * @name ui.router.util.$urlMatcherFactory#caseInsensitive
30425            * @methodOf ui.router.util.$urlMatcherFactory
30426            *
30427            * @description
30428            * Defines whether URL matching should be case sensitive (the default behavior), or not.
30429            *
30430            * @param {boolean} value `false` to match URL in a case sensitive manner; otherwise `true`;
30431            * @returns {boolean} the current value of caseInsensitive
30432            */
30433           this.caseInsensitive = function(value) {
30434             if (isDefined(value))
30435               isCaseInsensitive = value;
30436             return isCaseInsensitive;
30437           };
30438
30439           /**
30440            * @ngdoc function
30441            * @name ui.router.util.$urlMatcherFactory#strictMode
30442            * @methodOf ui.router.util.$urlMatcherFactory
30443            *
30444            * @description
30445            * Defines whether URLs should match trailing slashes, or not (the default behavior).
30446            *
30447            * @param {boolean=} value `false` to match trailing slashes in URLs, otherwise `true`.
30448            * @returns {boolean} the current value of strictMode
30449            */
30450           this.strictMode = function(value) {
30451             if (isDefined(value))
30452               isStrictMode = value;
30453             return isStrictMode;
30454           };
30455
30456           /**
30457            * @ngdoc function
30458            * @name ui.router.util.$urlMatcherFactory#defaultSquashPolicy
30459            * @methodOf ui.router.util.$urlMatcherFactory
30460            *
30461            * @description
30462            * Sets the default behavior when generating or matching URLs with default parameter values.
30463            *
30464            * @param {string} value A string that defines the default parameter URL squashing behavior.
30465            *    `nosquash`: When generating an href with a default parameter value, do not squash the parameter value from the URL
30466            *    `slash`: When generating an href with a default parameter value, squash (remove) the parameter value, and, if the
30467            *             parameter is surrounded by slashes, squash (remove) one slash from the URL
30468            *    any other string, e.g. "~": When generating an href with a default parameter value, squash (remove)
30469            *             the parameter value from the URL and replace it with this string.
30470            */
30471           this.defaultSquashPolicy = function(value) {
30472             if (!isDefined(value)) return defaultSquashPolicy;
30473             if (value !== true && value !== false && !isString(value))
30474               throw new Error("Invalid squash policy: " + value + ". Valid policies: false, true, arbitrary-string");
30475             defaultSquashPolicy = value;
30476             return value;
30477           };
30478
30479           /**
30480            * @ngdoc function
30481            * @name ui.router.util.$urlMatcherFactory#compile
30482            * @methodOf ui.router.util.$urlMatcherFactory
30483            *
30484            * @description
30485            * Creates a {@link ui.router.util.type:UrlMatcher `UrlMatcher`} for the specified pattern.
30486            *
30487            * @param {string} pattern  The URL pattern.
30488            * @param {Object} config  The config object hash.
30489            * @returns {UrlMatcher}  The UrlMatcher.
30490            */
30491           this.compile = function (pattern, config) {
30492             return new UrlMatcher(pattern, extend(getDefaultConfig(), config));
30493           };
30494
30495           /**
30496            * @ngdoc function
30497            * @name ui.router.util.$urlMatcherFactory#isMatcher
30498            * @methodOf ui.router.util.$urlMatcherFactory
30499            *
30500            * @description
30501            * Returns true if the specified object is a `UrlMatcher`, or false otherwise.
30502            *
30503            * @param {Object} object  The object to perform the type check against.
30504            * @returns {Boolean}  Returns `true` if the object matches the `UrlMatcher` interface, by
30505            *          implementing all the same methods.
30506            */
30507           this.isMatcher = function (o) {
30508             if (!isObject(o)) return false;
30509             var result = true;
30510
30511             forEach(UrlMatcher.prototype, function(val, name) {
30512               if (isFunction(val)) {
30513                 result = result && (isDefined(o[name]) && isFunction(o[name]));
30514               }
30515             });
30516             return result;
30517           };
30518
30519           /**
30520            * @ngdoc function
30521            * @name ui.router.util.$urlMatcherFactory#type
30522            * @methodOf ui.router.util.$urlMatcherFactory
30523            *
30524            * @description
30525            * Registers a custom {@link ui.router.util.type:Type `Type`} object that can be used to
30526            * generate URLs with typed parameters.
30527            *
30528            * @param {string} name  The type name.
30529            * @param {Object|Function} definition   The type definition. See
30530            *        {@link ui.router.util.type:Type `Type`} for information on the values accepted.
30531            * @param {Object|Function} definitionFn (optional) A function that is injected before the app
30532            *        runtime starts.  The result of this function is merged into the existing `definition`.
30533            *        See {@link ui.router.util.type:Type `Type`} for information on the values accepted.
30534            *
30535            * @returns {Object}  Returns `$urlMatcherFactoryProvider`.
30536            *
30537            * @example
30538            * This is a simple example of a custom type that encodes and decodes items from an
30539            * array, using the array index as the URL-encoded value:
30540            *
30541            * <pre>
30542            * var list = ['John', 'Paul', 'George', 'Ringo'];
30543            *
30544            * $urlMatcherFactoryProvider.type('listItem', {
30545            *   encode: function(item) {
30546            *     // Represent the list item in the URL using its corresponding index
30547            *     return list.indexOf(item);
30548            *   },
30549            *   decode: function(item) {
30550            *     // Look up the list item by index
30551            *     return list[parseInt(item, 10)];
30552            *   },
30553            *   is: function(item) {
30554            *     // Ensure the item is valid by checking to see that it appears
30555            *     // in the list
30556            *     return list.indexOf(item) > -1;
30557            *   }
30558            * });
30559            *
30560            * $stateProvider.state('list', {
30561            *   url: "/list/{item:listItem}",
30562            *   controller: function($scope, $stateParams) {
30563            *     console.log($stateParams.item);
30564            *   }
30565            * });
30566            *
30567            * // ...
30568            *
30569            * // Changes URL to '/list/3', logs "Ringo" to the console
30570            * $state.go('list', { item: "Ringo" });
30571            * </pre>
30572            *
30573            * This is a more complex example of a type that relies on dependency injection to
30574            * interact with services, and uses the parameter name from the URL to infer how to
30575            * handle encoding and decoding parameter values:
30576            *
30577            * <pre>
30578            * // Defines a custom type that gets a value from a service,
30579            * // where each service gets different types of values from
30580            * // a backend API:
30581            * $urlMatcherFactoryProvider.type('dbObject', {}, function(Users, Posts) {
30582            *
30583            *   // Matches up services to URL parameter names
30584            *   var services = {
30585            *     user: Users,
30586            *     post: Posts
30587            *   };
30588            *
30589            *   return {
30590            *     encode: function(object) {
30591            *       // Represent the object in the URL using its unique ID
30592            *       return object.id;
30593            *     },
30594            *     decode: function(value, key) {
30595            *       // Look up the object by ID, using the parameter
30596            *       // name (key) to call the correct service
30597            *       return services[key].findById(value);
30598            *     },
30599            *     is: function(object, key) {
30600            *       // Check that object is a valid dbObject
30601            *       return angular.isObject(object) && object.id && services[key];
30602            *     }
30603            *     equals: function(a, b) {
30604            *       // Check the equality of decoded objects by comparing
30605            *       // their unique IDs
30606            *       return a.id === b.id;
30607            *     }
30608            *   };
30609            * });
30610            *
30611            * // In a config() block, you can then attach URLs with
30612            * // type-annotated parameters:
30613            * $stateProvider.state('users', {
30614            *   url: "/users",
30615            *   // ...
30616            * }).state('users.item', {
30617            *   url: "/{user:dbObject}",
30618            *   controller: function($scope, $stateParams) {
30619            *     // $stateParams.user will now be an object returned from
30620            *     // the Users service
30621            *   },
30622            *   // ...
30623            * });
30624            * </pre>
30625            */
30626           this.type = function (name, definition, definitionFn) {
30627             if (!isDefined(definition)) return $types[name];
30628             if ($types.hasOwnProperty(name)) throw new Error("A type named '" + name + "' has already been defined.");
30629
30630             $types[name] = new Type(extend({ name: name }, definition));
30631             if (definitionFn) {
30632               typeQueue.push({ name: name, def: definitionFn });
30633               if (!enqueue) flushTypeQueue();
30634             }
30635             return this;
30636           };
30637
30638           // `flushTypeQueue()` waits until `$urlMatcherFactory` is injected before invoking the queued `definitionFn`s
30639           function flushTypeQueue() {
30640             while(typeQueue.length) {
30641               var type = typeQueue.shift();
30642               if (type.pattern) throw new Error("You cannot override a type's .pattern at runtime.");
30643               angular.extend($types[type.name], injector.invoke(type.def));
30644             }
30645           }
30646
30647           // Register default types. Store them in the prototype of $types.
30648           forEach(defaultTypes, function(type, name) { $types[name] = new Type(extend({name: name}, type)); });
30649           $types = inherit($types, {});
30650
30651           /* No need to document $get, since it returns this */
30652           this.$get = ['$injector', function ($injector) {
30653             injector = $injector;
30654             enqueue = false;
30655             flushTypeQueue();
30656
30657             forEach(defaultTypes, function(type, name) {
30658               if (!$types[name]) $types[name] = new Type(type);
30659             });
30660             return this;
30661           }];
30662
30663           this.Param = function Param(id, type, config, location) {
30664             var self = this;
30665             config = unwrapShorthand(config);
30666             type = getType(config, type, location);
30667             var arrayMode = getArrayMode();
30668             type = arrayMode ? type.$asArray(arrayMode, location === "search") : type;
30669             if (type.name === "string" && !arrayMode && location === "path" && config.value === undefined)
30670               config.value = ""; // for 0.2.x; in 0.3.0+ do not automatically default to ""
30671             var isOptional = config.value !== undefined;
30672             var squash = getSquashPolicy(config, isOptional);
30673             var replace = getReplace(config, arrayMode, isOptional, squash);
30674
30675             function unwrapShorthand(config) {
30676               var keys = isObject(config) ? objectKeys(config) : [];
30677               var isShorthand = indexOf(keys, "value") === -1 && indexOf(keys, "type") === -1 &&
30678                                 indexOf(keys, "squash") === -1 && indexOf(keys, "array") === -1;
30679               if (isShorthand) config = { value: config };
30680               config.$$fn = isInjectable(config.value) ? config.value : function () { return config.value; };
30681               return config;
30682             }
30683
30684             function getType(config, urlType, location) {
30685               if (config.type && urlType) throw new Error("Param '"+id+"' has two type configurations.");
30686               if (urlType) return urlType;
30687               if (!config.type) return (location === "config" ? $types.any : $types.string);
30688               return config.type instanceof Type ? config.type : new Type(config.type);
30689             }
30690
30691             // array config: param name (param[]) overrides default settings.  explicit config overrides param name.
30692             function getArrayMode() {
30693               var arrayDefaults = { array: (location === "search" ? "auto" : false) };
30694               var arrayParamNomenclature = id.match(/\[\]$/) ? { array: true } : {};
30695               return extend(arrayDefaults, arrayParamNomenclature, config).array;
30696             }
30697
30698             /**
30699              * returns false, true, or the squash value to indicate the "default parameter url squash policy".
30700              */
30701             function getSquashPolicy(config, isOptional) {
30702               var squash = config.squash;
30703               if (!isOptional || squash === false) return false;
30704               if (!isDefined(squash) || squash == null) return defaultSquashPolicy;
30705               if (squash === true || isString(squash)) return squash;
30706               throw new Error("Invalid squash policy: '" + squash + "'. Valid policies: false, true, or arbitrary string");
30707             }
30708
30709             function getReplace(config, arrayMode, isOptional, squash) {
30710               var replace, configuredKeys, defaultPolicy = [
30711                 { from: "",   to: (isOptional || arrayMode ? undefined : "") },
30712                 { from: null, to: (isOptional || arrayMode ? undefined : "") }
30713               ];
30714               replace = isArray(config.replace) ? config.replace : [];
30715               if (isString(squash))
30716                 replace.push({ from: squash, to: undefined });
30717               configuredKeys = map(replace, function(item) { return item.from; } );
30718               return filter(defaultPolicy, function(item) { return indexOf(configuredKeys, item.from) === -1; }).concat(replace);
30719             }
30720
30721             /**
30722              * [Internal] Get the default value of a parameter, which may be an injectable function.
30723              */
30724             function $$getDefaultValue() {
30725               if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
30726               var defaultValue = injector.invoke(config.$$fn);
30727               if (defaultValue !== null && defaultValue !== undefined && !self.type.is(defaultValue))
30728                 throw new Error("Default value (" + defaultValue + ") for parameter '" + self.id + "' is not an instance of Type (" + self.type.name + ")");
30729               return defaultValue;
30730             }
30731
30732             /**
30733              * [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the
30734              * default value, which may be the result of an injectable function.
30735              */
30736             function $value(value) {
30737               function hasReplaceVal(val) { return function(obj) { return obj.from === val; }; }
30738               function $replace(value) {
30739                 var replacement = map(filter(self.replace, hasReplaceVal(value)), function(obj) { return obj.to; });
30740                 return replacement.length ? replacement[0] : value;
30741               }
30742               value = $replace(value);
30743               return !isDefined(value) ? $$getDefaultValue() : self.type.$normalize(value);
30744             }
30745
30746             function toString() { return "{Param:" + id + " " + type + " squash: '" + squash + "' optional: " + isOptional + "}"; }
30747
30748             extend(this, {
30749               id: id,
30750               type: type,
30751               location: location,
30752               array: arrayMode,
30753               squash: squash,
30754               replace: replace,
30755               isOptional: isOptional,
30756               value: $value,
30757               dynamic: undefined,
30758               config: config,
30759               toString: toString
30760             });
30761           };
30762
30763           function ParamSet(params) {
30764             extend(this, params || {});
30765           }
30766
30767           ParamSet.prototype = {
30768             $$new: function() {
30769               return inherit(this, extend(new ParamSet(), { $$parent: this}));
30770             },
30771             $$keys: function () {
30772               var keys = [], chain = [], parent = this,
30773                 ignore = objectKeys(ParamSet.prototype);
30774               while (parent) { chain.push(parent); parent = parent.$$parent; }
30775               chain.reverse();
30776               forEach(chain, function(paramset) {
30777                 forEach(objectKeys(paramset), function(key) {
30778                     if (indexOf(keys, key) === -1 && indexOf(ignore, key) === -1) keys.push(key);
30779                 });
30780               });
30781               return keys;
30782             },
30783             $$values: function(paramValues) {
30784               var values = {}, self = this;
30785               forEach(self.$$keys(), function(key) {
30786                 values[key] = self[key].value(paramValues && paramValues[key]);
30787               });
30788               return values;
30789             },
30790             $$equals: function(paramValues1, paramValues2) {
30791               var equal = true, self = this;
30792               forEach(self.$$keys(), function(key) {
30793                 var left = paramValues1 && paramValues1[key], right = paramValues2 && paramValues2[key];
30794                 if (!self[key].type.equals(left, right)) equal = false;
30795               });
30796               return equal;
30797             },
30798             $$validates: function $$validate(paramValues) {
30799               var keys = this.$$keys(), i, param, rawVal, normalized, encoded;
30800               for (i = 0; i < keys.length; i++) {
30801                 param = this[keys[i]];
30802                 rawVal = paramValues[keys[i]];
30803                 if ((rawVal === undefined || rawVal === null) && param.isOptional)
30804                   break; // There was no parameter value, but the param is optional
30805                 normalized = param.type.$normalize(rawVal);
30806                 if (!param.type.is(normalized))
30807                   return false; // The value was not of the correct Type, and could not be decoded to the correct Type
30808                 encoded = param.type.encode(normalized);
30809                 if (angular.isString(encoded) && !param.type.pattern.exec(encoded))
30810                   return false; // The value was of the correct type, but when encoded, did not match the Type's regexp
30811               }
30812               return true;
30813             },
30814             $$parent: undefined
30815           };
30816
30817           this.ParamSet = ParamSet;
30818         }
30819
30820         // Register as a provider so it's available to other providers
30821         angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory);
30822         angular.module('ui.router.util').run(['$urlMatcherFactory', function($urlMatcherFactory) { }]);
30823
30824         /**
30825          * @ngdoc object
30826          * @name ui.router.router.$urlRouterProvider
30827          *
30828          * @requires ui.router.util.$urlMatcherFactoryProvider
30829          * @requires $locationProvider
30830          *
30831          * @description
30832          * `$urlRouterProvider` has the responsibility of watching `$location`. 
30833          * When `$location` changes it runs through a list of rules one by one until a 
30834          * match is found. `$urlRouterProvider` is used behind the scenes anytime you specify 
30835          * a url in a state configuration. All urls are compiled into a UrlMatcher object.
30836          *
30837          * There are several methods on `$urlRouterProvider` that make it useful to use directly
30838          * in your module config.
30839          */
30840         $UrlRouterProvider.$inject = ['$locationProvider', '$urlMatcherFactoryProvider'];
30841         function $UrlRouterProvider(   $locationProvider,   $urlMatcherFactory) {
30842           var rules = [], otherwise = null, interceptDeferred = false, listener;
30843
30844           // Returns a string that is a prefix of all strings matching the RegExp
30845           function regExpPrefix(re) {
30846             var prefix = /^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(re.source);
30847             return (prefix != null) ? prefix[1].replace(/\\(.)/g, "$1") : '';
30848           }
30849
30850           // Interpolates matched values into a String.replace()-style pattern
30851           function interpolate(pattern, match) {
30852             return pattern.replace(/\$(\$|\d{1,2})/, function (m, what) {
30853               return match[what === '$' ? 0 : Number(what)];
30854             });
30855           }
30856
30857           /**
30858            * @ngdoc function
30859            * @name ui.router.router.$urlRouterProvider#rule
30860            * @methodOf ui.router.router.$urlRouterProvider
30861            *
30862            * @description
30863            * Defines rules that are used by `$urlRouterProvider` to find matches for
30864            * specific URLs.
30865            *
30866            * @example
30867            * <pre>
30868            * var app = angular.module('app', ['ui.router.router']);
30869            *
30870            * app.config(function ($urlRouterProvider) {
30871            *   // Here's an example of how you might allow case insensitive urls
30872            *   $urlRouterProvider.rule(function ($injector, $location) {
30873            *     var path = $location.path(),
30874            *         normalized = path.toLowerCase();
30875            *
30876            *     if (path !== normalized) {
30877            *       return normalized;
30878            *     }
30879            *   });
30880            * });
30881            * </pre>
30882            *
30883            * @param {object} rule Handler function that takes `$injector` and `$location`
30884            * services as arguments. You can use them to return a valid path as a string.
30885            *
30886            * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance
30887            */
30888           this.rule = function (rule) {
30889             if (!isFunction(rule)) throw new Error("'rule' must be a function");
30890             rules.push(rule);
30891             return this;
30892           };
30893
30894           /**
30895            * @ngdoc object
30896            * @name ui.router.router.$urlRouterProvider#otherwise
30897            * @methodOf ui.router.router.$urlRouterProvider
30898            *
30899            * @description
30900            * Defines a path that is used when an invalid route is requested.
30901            *
30902            * @example
30903            * <pre>
30904            * var app = angular.module('app', ['ui.router.router']);
30905            *
30906            * app.config(function ($urlRouterProvider) {
30907            *   // if the path doesn't match any of the urls you configured
30908            *   // otherwise will take care of routing the user to the
30909            *   // specified url
30910            *   $urlRouterProvider.otherwise('/index');
30911            *
30912            *   // Example of using function rule as param
30913            *   $urlRouterProvider.otherwise(function ($injector, $location) {
30914            *     return '/a/valid/url';
30915            *   });
30916            * });
30917            * </pre>
30918            *
30919            * @param {string|object} rule The url path you want to redirect to or a function 
30920            * rule that returns the url path. The function version is passed two params: 
30921            * `$injector` and `$location` services, and must return a url string.
30922            *
30923            * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance
30924            */
30925           this.otherwise = function (rule) {
30926             if (isString(rule)) {
30927               var redirect = rule;
30928               rule = function () { return redirect; };
30929             }
30930             else if (!isFunction(rule)) throw new Error("'rule' must be a function");
30931             otherwise = rule;
30932             return this;
30933           };
30934
30935
30936           function handleIfMatch($injector, handler, match) {
30937             if (!match) return false;
30938             var result = $injector.invoke(handler, handler, { $match: match });
30939             return isDefined(result) ? result : true;
30940           }
30941
30942           /**
30943            * @ngdoc function
30944            * @name ui.router.router.$urlRouterProvider#when
30945            * @methodOf ui.router.router.$urlRouterProvider
30946            *
30947            * @description
30948            * Registers a handler for a given url matching. if handle is a string, it is
30949            * treated as a redirect, and is interpolated according to the syntax of match
30950            * (i.e. like `String.replace()` for `RegExp`, or like a `UrlMatcher` pattern otherwise).
30951            *
30952            * If the handler is a function, it is injectable. It gets invoked if `$location`
30953            * matches. You have the option of inject the match object as `$match`.
30954            *
30955            * The handler can return
30956            *
30957            * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter`
30958            *   will continue trying to find another one that matches.
30959            * - **string** which is treated as a redirect and passed to `$location.url()`
30960            * - **void** or any **truthy** value tells `$urlRouter` that the url was handled.
30961            *
30962            * @example
30963            * <pre>
30964            * var app = angular.module('app', ['ui.router.router']);
30965            *
30966            * app.config(function ($urlRouterProvider) {
30967            *   $urlRouterProvider.when($state.url, function ($match, $stateParams) {
30968            *     if ($state.$current.navigable !== state ||
30969            *         !equalForKeys($match, $stateParams) {
30970            *      $state.transitionTo(state, $match, false);
30971            *     }
30972            *   });
30973            * });
30974            * </pre>
30975            *
30976            * @param {string|object} what The incoming path that you want to redirect.
30977            * @param {string|object} handler The path you want to redirect your user to.
30978            */
30979           this.when = function (what, handler) {
30980             var redirect, handlerIsString = isString(handler);
30981             if (isString(what)) what = $urlMatcherFactory.compile(what);
30982
30983             if (!handlerIsString && !isFunction(handler) && !isArray(handler))
30984               throw new Error("invalid 'handler' in when()");
30985
30986             var strategies = {
30987               matcher: function (what, handler) {
30988                 if (handlerIsString) {
30989                   redirect = $urlMatcherFactory.compile(handler);
30990                   handler = ['$match', function ($match) { return redirect.format($match); }];
30991                 }
30992                 return extend(function ($injector, $location) {
30993                   return handleIfMatch($injector, handler, what.exec($location.path(), $location.search()));
30994                 }, {
30995                   prefix: isString(what.prefix) ? what.prefix : ''
30996                 });
30997               },
30998               regex: function (what, handler) {
30999                 if (what.global || what.sticky) throw new Error("when() RegExp must not be global or sticky");
31000
31001                 if (handlerIsString) {
31002                   redirect = handler;
31003                   handler = ['$match', function ($match) { return interpolate(redirect, $match); }];
31004                 }
31005                 return extend(function ($injector, $location) {
31006                   return handleIfMatch($injector, handler, what.exec($location.path()));
31007                 }, {
31008                   prefix: regExpPrefix(what)
31009                 });
31010               }
31011             };
31012
31013             var check = { matcher: $urlMatcherFactory.isMatcher(what), regex: what instanceof RegExp };
31014
31015             for (var n in check) {
31016               if (check[n]) return this.rule(strategies[n](what, handler));
31017             }
31018
31019             throw new Error("invalid 'what' in when()");
31020           };
31021
31022           /**
31023            * @ngdoc function
31024            * @name ui.router.router.$urlRouterProvider#deferIntercept
31025            * @methodOf ui.router.router.$urlRouterProvider
31026            *
31027            * @description
31028            * Disables (or enables) deferring location change interception.
31029            *
31030            * If you wish to customize the behavior of syncing the URL (for example, if you wish to
31031            * defer a transition but maintain the current URL), call this method at configuration time.
31032            * Then, at run time, call `$urlRouter.listen()` after you have configured your own
31033            * `$locationChangeSuccess` event handler.
31034            *
31035            * @example
31036            * <pre>
31037            * var app = angular.module('app', ['ui.router.router']);
31038            *
31039            * app.config(function ($urlRouterProvider) {
31040            *
31041            *   // Prevent $urlRouter from automatically intercepting URL changes;
31042            *   // this allows you to configure custom behavior in between
31043            *   // location changes and route synchronization:
31044            *   $urlRouterProvider.deferIntercept();
31045            *
31046            * }).run(function ($rootScope, $urlRouter, UserService) {
31047            *
31048            *   $rootScope.$on('$locationChangeSuccess', function(e) {
31049            *     // UserService is an example service for managing user state
31050            *     if (UserService.isLoggedIn()) return;
31051            *
31052            *     // Prevent $urlRouter's default handler from firing
31053            *     e.preventDefault();
31054            *
31055            *     UserService.handleLogin().then(function() {
31056            *       // Once the user has logged in, sync the current URL
31057            *       // to the router:
31058            *       $urlRouter.sync();
31059            *     });
31060            *   });
31061            *
31062            *   // Configures $urlRouter's listener *after* your custom listener
31063            *   $urlRouter.listen();
31064            * });
31065            * </pre>
31066            *
31067            * @param {boolean} defer Indicates whether to defer location change interception. Passing
31068                     no parameter is equivalent to `true`.
31069            */
31070           this.deferIntercept = function (defer) {
31071             if (defer === undefined) defer = true;
31072             interceptDeferred = defer;
31073           };
31074
31075           /**
31076            * @ngdoc object
31077            * @name ui.router.router.$urlRouter
31078            *
31079            * @requires $location
31080            * @requires $rootScope
31081            * @requires $injector
31082            * @requires $browser
31083            *
31084            * @description
31085            *
31086            */
31087           this.$get = $get;
31088           $get.$inject = ['$location', '$rootScope', '$injector', '$browser'];
31089           function $get(   $location,   $rootScope,   $injector,   $browser) {
31090
31091             var baseHref = $browser.baseHref(), location = $location.url(), lastPushedUrl;
31092
31093             function appendBasePath(url, isHtml5, absolute) {
31094               if (baseHref === '/') return url;
31095               if (isHtml5) return baseHref.slice(0, -1) + url;
31096               if (absolute) return baseHref.slice(1) + url;
31097               return url;
31098             }
31099
31100             // TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree
31101             function update(evt) {
31102               if (evt && evt.defaultPrevented) return;
31103               var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl;
31104               lastPushedUrl = undefined;
31105               // TODO: Re-implement this in 1.0 for https://github.com/angular-ui/ui-router/issues/1573
31106               //if (ignoreUpdate) return true;
31107
31108               function check(rule) {
31109                 var handled = rule($injector, $location);
31110
31111                 if (!handled) return false;
31112                 if (isString(handled)) $location.replace().url(handled);
31113                 return true;
31114               }
31115               var n = rules.length, i;
31116
31117               for (i = 0; i < n; i++) {
31118                 if (check(rules[i])) return;
31119               }
31120               // always check otherwise last to allow dynamic updates to the set of rules
31121               if (otherwise) check(otherwise);
31122             }
31123
31124             function listen() {
31125               listener = listener || $rootScope.$on('$locationChangeSuccess', update);
31126               return listener;
31127             }
31128
31129             if (!interceptDeferred) listen();
31130
31131             return {
31132               /**
31133                * @ngdoc function
31134                * @name ui.router.router.$urlRouter#sync
31135                * @methodOf ui.router.router.$urlRouter
31136                *
31137                * @description
31138                * Triggers an update; the same update that happens when the address bar url changes, aka `$locationChangeSuccess`.
31139                * This method is useful when you need to use `preventDefault()` on the `$locationChangeSuccess` event,
31140                * perform some custom logic (route protection, auth, config, redirection, etc) and then finally proceed
31141                * with the transition by calling `$urlRouter.sync()`.
31142                *
31143                * @example
31144                * <pre>
31145                * angular.module('app', ['ui.router'])
31146                *   .run(function($rootScope, $urlRouter) {
31147                *     $rootScope.$on('$locationChangeSuccess', function(evt) {
31148                *       // Halt state change from even starting
31149                *       evt.preventDefault();
31150                *       // Perform custom logic
31151                *       var meetsRequirement = ...
31152                *       // Continue with the update and state transition if logic allows
31153                *       if (meetsRequirement) $urlRouter.sync();
31154                *     });
31155                * });
31156                * </pre>
31157                */
31158               sync: function() {
31159                 update();
31160               },
31161
31162               listen: function() {
31163                 return listen();
31164               },
31165
31166               update: function(read) {
31167                 if (read) {
31168                   location = $location.url();
31169                   return;
31170                 }
31171                 if ($location.url() === location) return;
31172
31173                 $location.url(location);
31174                 $location.replace();
31175               },
31176
31177               push: function(urlMatcher, params, options) {
31178                  var url = urlMatcher.format(params || {});
31179
31180                 // Handle the special hash param, if needed
31181                 if (url !== null && params && params['#']) {
31182                     url += '#' + params['#'];
31183                 }
31184
31185                 $location.url(url);
31186                 lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined;
31187                 if (options && options.replace) $location.replace();
31188               },
31189
31190               /**
31191                * @ngdoc function
31192                * @name ui.router.router.$urlRouter#href
31193                * @methodOf ui.router.router.$urlRouter
31194                *
31195                * @description
31196                * A URL generation method that returns the compiled URL for a given
31197                * {@link ui.router.util.type:UrlMatcher `UrlMatcher`}, populated with the provided parameters.
31198                *
31199                * @example
31200                * <pre>
31201                * $bob = $urlRouter.href(new UrlMatcher("/about/:person"), {
31202                *   person: "bob"
31203                * });
31204                * // $bob == "/about/bob";
31205                * </pre>
31206                *
31207                * @param {UrlMatcher} urlMatcher The `UrlMatcher` object which is used as the template of the URL to generate.
31208                * @param {object=} params An object of parameter values to fill the matcher's required parameters.
31209                * @param {object=} options Options object. The options are:
31210                *
31211                * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
31212                *
31213                * @returns {string} Returns the fully compiled URL, or `null` if `params` fail validation against `urlMatcher`
31214                */
31215               href: function(urlMatcher, params, options) {
31216                 if (!urlMatcher.validates(params)) return null;
31217
31218                 var isHtml5 = $locationProvider.html5Mode();
31219                 if (angular.isObject(isHtml5)) {
31220                   isHtml5 = isHtml5.enabled;
31221                 }
31222                 
31223                 var url = urlMatcher.format(params);
31224                 options = options || {};
31225
31226                 if (!isHtml5 && url !== null) {
31227                   url = "#" + $locationProvider.hashPrefix() + url;
31228                 }
31229
31230                 // Handle special hash param, if needed
31231                 if (url !== null && params && params['#']) {
31232                   url += '#' + params['#'];
31233                 }
31234
31235                 url = appendBasePath(url, isHtml5, options.absolute);
31236
31237                 if (!options.absolute || !url) {
31238                   return url;
31239                 }
31240
31241                 var slash = (!isHtml5 && url ? '/' : ''), port = $location.port();
31242                 port = (port === 80 || port === 443 ? '' : ':' + port);
31243
31244                 return [$location.protocol(), '://', $location.host(), port, slash, url].join('');
31245               }
31246             };
31247           }
31248         }
31249
31250         angular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider);
31251
31252         /**
31253          * @ngdoc object
31254          * @name ui.router.state.$stateProvider
31255          *
31256          * @requires ui.router.router.$urlRouterProvider
31257          * @requires ui.router.util.$urlMatcherFactoryProvider
31258          *
31259          * @description
31260          * The new `$stateProvider` works similar to Angular's v1 router, but it focuses purely
31261          * on state.
31262          *
31263          * A state corresponds to a "place" in the application in terms of the overall UI and
31264          * navigation. A state describes (via the controller / template / view properties) what
31265          * the UI looks like and does at that place.
31266          *
31267          * States often have things in common, and the primary way of factoring out these
31268          * commonalities in this model is via the state hierarchy, i.e. parent/child states aka
31269          * nested states.
31270          *
31271          * The `$stateProvider` provides interfaces to declare these states for your app.
31272          */
31273         $StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];
31274         function $StateProvider(   $urlRouterProvider,   $urlMatcherFactory) {
31275
31276           var root, states = {}, $state, queue = {}, abstractKey = 'abstract';
31277
31278           // Builds state properties from definition passed to registerState()
31279           var stateBuilder = {
31280
31281             // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.
31282             // state.children = [];
31283             // if (parent) parent.children.push(state);
31284             parent: function(state) {
31285               if (isDefined(state.parent) && state.parent) return findState(state.parent);
31286               // regex matches any valid composite state name
31287               // would match "contact.list" but not "contacts"
31288               var compositeName = /^(.+)\.[^.]+$/.exec(state.name);
31289               return compositeName ? findState(compositeName[1]) : root;
31290             },
31291
31292             // inherit 'data' from parent and override by own values (if any)
31293             data: function(state) {
31294               if (state.parent && state.parent.data) {
31295                 state.data = state.self.data = extend({}, state.parent.data, state.data);
31296               }
31297               return state.data;
31298             },
31299
31300             // Build a URLMatcher if necessary, either via a relative or absolute URL
31301             url: function(state) {
31302               var url = state.url, config = { params: state.params || {} };
31303
31304               if (isString(url)) {
31305                 if (url.charAt(0) == '^') return $urlMatcherFactory.compile(url.substring(1), config);
31306                 return (state.parent.navigable || root).url.concat(url, config);
31307               }
31308
31309               if (!url || $urlMatcherFactory.isMatcher(url)) return url;
31310               throw new Error("Invalid url '" + url + "' in state '" + state + "'");
31311             },
31312
31313             // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
31314             navigable: function(state) {
31315               return state.url ? state : (state.parent ? state.parent.navigable : null);
31316             },
31317
31318             // Own parameters for this state. state.url.params is already built at this point. Create and add non-url params
31319             ownParams: function(state) {
31320               var params = state.url && state.url.params || new $$UMFP.ParamSet();
31321               forEach(state.params || {}, function(config, id) {
31322                 if (!params[id]) params[id] = new $$UMFP.Param(id, null, config, "config");
31323               });
31324               return params;
31325             },
31326
31327             // Derive parameters for this state and ensure they're a super-set of parent's parameters
31328             params: function(state) {
31329               return state.parent && state.parent.params ? extend(state.parent.params.$$new(), state.ownParams) : new $$UMFP.ParamSet();
31330             },
31331
31332             // If there is no explicit multi-view configuration, make one up so we don't have
31333             // to handle both cases in the view directive later. Note that having an explicit
31334             // 'views' property will mean the default unnamed view properties are ignored. This
31335             // is also a good time to resolve view names to absolute names, so everything is a
31336             // straight lookup at link time.
31337             views: function(state) {
31338               var views = {};
31339
31340               forEach(isDefined(state.views) ? state.views : { '': state }, function (view, name) {
31341                 if (name.indexOf('@') < 0) name += '@' + state.parent.name;
31342                 views[name] = view;
31343               });
31344               return views;
31345             },
31346
31347             // Keep a full path from the root down to this state as this is needed for state activation.
31348             path: function(state) {
31349               return state.parent ? state.parent.path.concat(state) : []; // exclude root from path
31350             },
31351
31352             // Speed up $state.contains() as it's used a lot
31353             includes: function(state) {
31354               var includes = state.parent ? extend({}, state.parent.includes) : {};
31355               includes[state.name] = true;
31356               return includes;
31357             },
31358
31359             $delegates: {}
31360           };
31361
31362           function isRelative(stateName) {
31363             return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0;
31364           }
31365
31366           function findState(stateOrName, base) {
31367             if (!stateOrName) return undefined;
31368
31369             var isStr = isString(stateOrName),
31370                 name  = isStr ? stateOrName : stateOrName.name,
31371                 path  = isRelative(name);
31372
31373             if (path) {
31374               if (!base) throw new Error("No reference point given for path '"  + name + "'");
31375               base = findState(base);
31376               
31377               var rel = name.split("."), i = 0, pathLength = rel.length, current = base;
31378
31379               for (; i < pathLength; i++) {
31380                 if (rel[i] === "" && i === 0) {
31381                   current = base;
31382                   continue;
31383                 }
31384                 if (rel[i] === "^") {
31385                   if (!current.parent) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'");
31386                   current = current.parent;
31387                   continue;
31388                 }
31389                 break;
31390               }
31391               rel = rel.slice(i).join(".");
31392               name = current.name + (current.name && rel ? "." : "") + rel;
31393             }
31394             var state = states[name];
31395
31396             if (state && (isStr || (!isStr && (state === stateOrName || state.self === stateOrName)))) {
31397               return state;
31398             }
31399             return undefined;
31400           }
31401
31402           function queueState(parentName, state) {
31403             if (!queue[parentName]) {
31404               queue[parentName] = [];
31405             }
31406             queue[parentName].push(state);
31407           }
31408
31409           function flushQueuedChildren(parentName) {
31410             var queued = queue[parentName] || [];
31411             while(queued.length) {
31412               registerState(queued.shift());
31413             }
31414           }
31415
31416           function registerState(state) {
31417             // Wrap a new object around the state so we can store our private details easily.
31418             state = inherit(state, {
31419               self: state,
31420               resolve: state.resolve || {},
31421               toString: function() { return this.name; }
31422             });
31423
31424             var name = state.name;
31425             if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name");
31426             if (states.hasOwnProperty(name)) throw new Error("State '" + name + "'' is already defined");
31427
31428             // Get parent name
31429             var parentName = (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.'))
31430                 : (isString(state.parent)) ? state.parent
31431                 : (isObject(state.parent) && isString(state.parent.name)) ? state.parent.name
31432                 : '';
31433
31434             // If parent is not registered yet, add state to queue and register later
31435             if (parentName && !states[parentName]) {
31436               return queueState(parentName, state.self);
31437             }
31438
31439             for (var key in stateBuilder) {
31440               if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]);
31441             }
31442             states[name] = state;
31443
31444             // Register the state in the global state list and with $urlRouter if necessary.
31445             if (!state[abstractKey] && state.url) {
31446               $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
31447                 if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
31448                   $state.transitionTo(state, $match, { inherit: true, location: false });
31449                 }
31450               }]);
31451             }
31452
31453             // Register any queued children
31454             flushQueuedChildren(name);
31455
31456             return state;
31457           }
31458
31459           // Checks text to see if it looks like a glob.
31460           function isGlob (text) {
31461             return text.indexOf('*') > -1;
31462           }
31463
31464           // Returns true if glob matches current $state name.
31465           function doesStateMatchGlob (glob) {
31466             var globSegments = glob.split('.'),
31467                 segments = $state.$current.name.split('.');
31468
31469             //match single stars
31470             for (var i = 0, l = globSegments.length; i < l; i++) {
31471               if (globSegments[i] === '*') {
31472                 segments[i] = '*';
31473               }
31474             }
31475
31476             //match greedy starts
31477             if (globSegments[0] === '**') {
31478                segments = segments.slice(indexOf(segments, globSegments[1]));
31479                segments.unshift('**');
31480             }
31481             //match greedy ends
31482             if (globSegments[globSegments.length - 1] === '**') {
31483                segments.splice(indexOf(segments, globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE);
31484                segments.push('**');
31485             }
31486
31487             if (globSegments.length != segments.length) {
31488               return false;
31489             }
31490
31491             return segments.join('') === globSegments.join('');
31492           }
31493
31494
31495           // Implicit root state that is always active
31496           root = registerState({
31497             name: '',
31498             url: '^',
31499             views: null,
31500             'abstract': true
31501           });
31502           root.navigable = null;
31503
31504
31505           /**
31506            * @ngdoc function
31507            * @name ui.router.state.$stateProvider#decorator
31508            * @methodOf ui.router.state.$stateProvider
31509            *
31510            * @description
31511            * Allows you to extend (carefully) or override (at your own peril) the 
31512            * `stateBuilder` object used internally by `$stateProvider`. This can be used 
31513            * to add custom functionality to ui-router, for example inferring templateUrl 
31514            * based on the state name.
31515            *
31516            * When passing only a name, it returns the current (original or decorated) builder
31517            * function that matches `name`.
31518            *
31519            * The builder functions that can be decorated are listed below. Though not all
31520            * necessarily have a good use case for decoration, that is up to you to decide.
31521            *
31522            * In addition, users can attach custom decorators, which will generate new 
31523            * properties within the state's internal definition. There is currently no clear 
31524            * use-case for this beyond accessing internal states (i.e. $state.$current), 
31525            * however, expect this to become increasingly relevant as we introduce additional 
31526            * meta-programming features.
31527            *
31528            * **Warning**: Decorators should not be interdependent because the order of 
31529            * execution of the builder functions in non-deterministic. Builder functions 
31530            * should only be dependent on the state definition object and super function.
31531            *
31532            *
31533            * Existing builder functions and current return values:
31534            *
31535            * - **parent** `{object}` - returns the parent state object.
31536            * - **data** `{object}` - returns state data, including any inherited data that is not
31537            *   overridden by own values (if any).
31538            * - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher}
31539            *   or `null`.
31540            * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is 
31541            *   navigable).
31542            * - **params** `{object}` - returns an array of state params that are ensured to 
31543            *   be a super-set of parent's params.
31544            * - **views** `{object}` - returns a views object where each key is an absolute view 
31545            *   name (i.e. "viewName@stateName") and each value is the config object 
31546            *   (template, controller) for the view. Even when you don't use the views object 
31547            *   explicitly on a state config, one is still created for you internally.
31548            *   So by decorating this builder function you have access to decorating template 
31549            *   and controller properties.
31550            * - **ownParams** `{object}` - returns an array of params that belong to the state, 
31551            *   not including any params defined by ancestor states.
31552            * - **path** `{string}` - returns the full path from the root down to this state. 
31553            *   Needed for state activation.
31554            * - **includes** `{object}` - returns an object that includes every state that 
31555            *   would pass a `$state.includes()` test.
31556            *
31557            * @example
31558            * <pre>
31559            * // Override the internal 'views' builder with a function that takes the state
31560            * // definition, and a reference to the internal function being overridden:
31561            * $stateProvider.decorator('views', function (state, parent) {
31562            *   var result = {},
31563            *       views = parent(state);
31564            *
31565            *   angular.forEach(views, function (config, name) {
31566            *     var autoName = (state.name + '.' + name).replace('.', '/');
31567            *     config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';
31568            *     result[name] = config;
31569            *   });
31570            *   return result;
31571            * });
31572            *
31573            * $stateProvider.state('home', {
31574            *   views: {
31575            *     'contact.list': { controller: 'ListController' },
31576            *     'contact.item': { controller: 'ItemController' }
31577            *   }
31578            * });
31579            *
31580            * // ...
31581            *
31582            * $state.go('home');
31583            * // Auto-populates list and item views with /partials/home/contact/list.html,
31584            * // and /partials/home/contact/item.html, respectively.
31585            * </pre>
31586            *
31587            * @param {string} name The name of the builder function to decorate. 
31588            * @param {object} func A function that is responsible for decorating the original 
31589            * builder function. The function receives two parameters:
31590            *
31591            *   - `{object}` - state - The state config object.
31592            *   - `{object}` - super - The original builder function.
31593            *
31594            * @return {object} $stateProvider - $stateProvider instance
31595            */
31596           this.decorator = decorator;
31597           function decorator(name, func) {
31598             /*jshint validthis: true */
31599             if (isString(name) && !isDefined(func)) {
31600               return stateBuilder[name];
31601             }
31602             if (!isFunction(func) || !isString(name)) {
31603               return this;
31604             }
31605             if (stateBuilder[name] && !stateBuilder.$delegates[name]) {
31606               stateBuilder.$delegates[name] = stateBuilder[name];
31607             }
31608             stateBuilder[name] = func;
31609             return this;
31610           }
31611
31612           /**
31613            * @ngdoc function
31614            * @name ui.router.state.$stateProvider#state
31615            * @methodOf ui.router.state.$stateProvider
31616            *
31617            * @description
31618            * Registers a state configuration under a given state name. The stateConfig object
31619            * has the following acceptable properties.
31620            *
31621            * @param {string} name A unique state name, e.g. "home", "about", "contacts".
31622            * To create a parent/child state use a dot, e.g. "about.sales", "home.newest".
31623            * @param {object} stateConfig State configuration object.
31624            * @param {string|function=} stateConfig.template
31625            * <a id='template'></a>
31626            *   html template as a string or a function that returns
31627            *   an html template as a string which should be used by the uiView directives. This property 
31628            *   takes precedence over templateUrl.
31629            *   
31630            *   If `template` is a function, it will be called with the following parameters:
31631            *
31632            *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by
31633            *     applying the current state
31634            *
31635            * <pre>template:
31636            *   "<h1>inline template definition</h1>" +
31637            *   "<div ui-view></div>"</pre>
31638            * <pre>template: function(params) {
31639            *       return "<h1>generated template</h1>"; }</pre>
31640            * </div>
31641            *
31642            * @param {string|function=} stateConfig.templateUrl
31643            * <a id='templateUrl'></a>
31644            *
31645            *   path or function that returns a path to an html
31646            *   template that should be used by uiView.
31647            *   
31648            *   If `templateUrl` is a function, it will be called with the following parameters:
31649            *
31650            *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by 
31651            *     applying the current state
31652            *
31653            * <pre>templateUrl: "home.html"</pre>
31654            * <pre>templateUrl: function(params) {
31655            *     return myTemplates[params.pageId]; }</pre>
31656            *
31657            * @param {function=} stateConfig.templateProvider
31658            * <a id='templateProvider'></a>
31659            *    Provider function that returns HTML content string.
31660            * <pre> templateProvider:
31661            *       function(MyTemplateService, params) {
31662            *         return MyTemplateService.getTemplate(params.pageId);
31663            *       }</pre>
31664            *
31665            * @param {string|function=} stateConfig.controller
31666            * <a id='controller'></a>
31667            *
31668            *  Controller fn that should be associated with newly
31669            *   related scope or the name of a registered controller if passed as a string.
31670            *   Optionally, the ControllerAs may be declared here.
31671            * <pre>controller: "MyRegisteredController"</pre>
31672            * <pre>controller:
31673            *     "MyRegisteredController as fooCtrl"}</pre>
31674            * <pre>controller: function($scope, MyService) {
31675            *     $scope.data = MyService.getData(); }</pre>
31676            *
31677            * @param {function=} stateConfig.controllerProvider
31678            * <a id='controllerProvider'></a>
31679            *
31680            * Injectable provider function that returns the actual controller or string.
31681            * <pre>controllerProvider:
31682            *   function(MyResolveData) {
31683            *     if (MyResolveData.foo)
31684            *       return "FooCtrl"
31685            *     else if (MyResolveData.bar)
31686            *       return "BarCtrl";
31687            *     else return function($scope) {
31688            *       $scope.baz = "Qux";
31689            *     }
31690            *   }</pre>
31691            *
31692            * @param {string=} stateConfig.controllerAs
31693            * <a id='controllerAs'></a>
31694            * 
31695            * A controller alias name. If present the controller will be
31696            *   published to scope under the controllerAs name.
31697            * <pre>controllerAs: "myCtrl"</pre>
31698            *
31699            * @param {string|object=} stateConfig.parent
31700            * <a id='parent'></a>
31701            * Optionally specifies the parent state of this state.
31702            *
31703            * <pre>parent: 'parentState'</pre>
31704            * <pre>parent: parentState // JS variable</pre>
31705            *
31706            * @param {object=} stateConfig.resolve
31707            * <a id='resolve'></a>
31708            *
31709            * An optional map&lt;string, function&gt; of dependencies which
31710            *   should be injected into the controller. If any of these dependencies are promises, 
31711            *   the router will wait for them all to be resolved before the controller is instantiated.
31712            *   If all the promises are resolved successfully, the $stateChangeSuccess event is fired
31713            *   and the values of the resolved promises are injected into any controllers that reference them.
31714            *   If any  of the promises are rejected the $stateChangeError event is fired.
31715            *
31716            *   The map object is:
31717            *   
31718            *   - key - {string}: name of dependency to be injected into controller
31719            *   - factory - {string|function}: If string then it is alias for service. Otherwise if function, 
31720            *     it is injected and return value it treated as dependency. If result is a promise, it is 
31721            *     resolved before its value is injected into controller.
31722            *
31723            * <pre>resolve: {
31724            *     myResolve1:
31725            *       function($http, $stateParams) {
31726            *         return $http.get("/api/foos/"+stateParams.fooID);
31727            *       }
31728            *     }</pre>
31729            *
31730            * @param {string=} stateConfig.url
31731            * <a id='url'></a>
31732            *
31733            *   A url fragment with optional parameters. When a state is navigated or
31734            *   transitioned to, the `$stateParams` service will be populated with any 
31735            *   parameters that were passed.
31736            *
31737            *   (See {@link ui.router.util.type:UrlMatcher UrlMatcher} `UrlMatcher`} for
31738            *   more details on acceptable patterns )
31739            *
31740            * examples:
31741            * <pre>url: "/home"
31742            * url: "/users/:userid"
31743            * url: "/books/{bookid:[a-zA-Z_-]}"
31744            * url: "/books/{categoryid:int}"
31745            * url: "/books/{publishername:string}/{categoryid:int}"
31746            * url: "/messages?before&after"
31747            * url: "/messages?{before:date}&{after:date}"
31748            * url: "/messages/:mailboxid?{before:date}&{after:date}"
31749            * </pre>
31750            *
31751            * @param {object=} stateConfig.views
31752            * <a id='views'></a>
31753            * an optional map&lt;string, object&gt; which defined multiple views, or targets views
31754            * manually/explicitly.
31755            *
31756            * Examples:
31757            *
31758            * Targets three named `ui-view`s in the parent state's template
31759            * <pre>views: {
31760            *     header: {
31761            *       controller: "headerCtrl",
31762            *       templateUrl: "header.html"
31763            *     }, body: {
31764            *       controller: "bodyCtrl",
31765            *       templateUrl: "body.html"
31766            *     }, footer: {
31767            *       controller: "footCtrl",
31768            *       templateUrl: "footer.html"
31769            *     }
31770            *   }</pre>
31771            *
31772            * Targets named `ui-view="header"` from grandparent state 'top''s template, and named `ui-view="body" from parent state's template.
31773            * <pre>views: {
31774            *     'header@top': {
31775            *       controller: "msgHeaderCtrl",
31776            *       templateUrl: "msgHeader.html"
31777            *     }, 'body': {
31778            *       controller: "messagesCtrl",
31779            *       templateUrl: "messages.html"
31780            *     }
31781            *   }</pre>
31782            *
31783            * @param {boolean=} [stateConfig.abstract=false]
31784            * <a id='abstract'></a>
31785            * An abstract state will never be directly activated,
31786            *   but can provide inherited properties to its common children states.
31787            * <pre>abstract: true</pre>
31788            *
31789            * @param {function=} stateConfig.onEnter
31790            * <a id='onEnter'></a>
31791            *
31792            * Callback function for when a state is entered. Good way
31793            *   to trigger an action or dispatch an event, such as opening a dialog.
31794            * If minifying your scripts, make sure to explictly annotate this function,
31795            * because it won't be automatically annotated by your build tools.
31796            *
31797            * <pre>onEnter: function(MyService, $stateParams) {
31798            *     MyService.foo($stateParams.myParam);
31799            * }</pre>
31800            *
31801            * @param {function=} stateConfig.onExit
31802            * <a id='onExit'></a>
31803            *
31804            * Callback function for when a state is exited. Good way to
31805            *   trigger an action or dispatch an event, such as opening a dialog.
31806            * If minifying your scripts, make sure to explictly annotate this function,
31807            * because it won't be automatically annotated by your build tools.
31808            *
31809            * <pre>onExit: function(MyService, $stateParams) {
31810            *     MyService.cleanup($stateParams.myParam);
31811            * }</pre>
31812            *
31813            * @param {boolean=} [stateConfig.reloadOnSearch=true]
31814            * <a id='reloadOnSearch'></a>
31815            *
31816            * If `false`, will not retrigger the same state
31817            *   just because a search/query parameter has changed (via $location.search() or $location.hash()). 
31818            *   Useful for when you'd like to modify $location.search() without triggering a reload.
31819            * <pre>reloadOnSearch: false</pre>
31820            *
31821            * @param {object=} stateConfig.data
31822            * <a id='data'></a>
31823            *
31824            * Arbitrary data object, useful for custom configuration.  The parent state's `data` is
31825            *   prototypally inherited.  In other words, adding a data property to a state adds it to
31826            *   the entire subtree via prototypal inheritance.
31827            *
31828            * <pre>data: {
31829            *     requiredRole: 'foo'
31830            * } </pre>
31831            *
31832            * @param {object=} stateConfig.params
31833            * <a id='params'></a>
31834            *
31835            * A map which optionally configures parameters declared in the `url`, or
31836            *   defines additional non-url parameters.  For each parameter being
31837            *   configured, add a configuration object keyed to the name of the parameter.
31838            *
31839            *   Each parameter configuration object may contain the following properties:
31840            *
31841            *   - ** value ** - {object|function=}: specifies the default value for this
31842            *     parameter.  This implicitly sets this parameter as optional.
31843            *
31844            *     When UI-Router routes to a state and no value is
31845            *     specified for this parameter in the URL or transition, the
31846            *     default value will be used instead.  If `value` is a function,
31847            *     it will be injected and invoked, and the return value used.
31848            *
31849            *     *Note*: `undefined` is treated as "no default value" while `null`
31850            *     is treated as "the default value is `null`".
31851            *
31852            *     *Shorthand*: If you only need to configure the default value of the
31853            *     parameter, you may use a shorthand syntax.   In the **`params`**
31854            *     map, instead mapping the param name to a full parameter configuration
31855            *     object, simply set map it to the default parameter value, e.g.:
31856            *
31857            * <pre>// define a parameter's default value
31858            * params: {
31859            *     param1: { value: "defaultValue" }
31860            * }
31861            * // shorthand default values
31862            * params: {
31863            *     param1: "defaultValue",
31864            *     param2: "param2Default"
31865            * }</pre>
31866            *
31867            *   - ** array ** - {boolean=}: *(default: false)* If true, the param value will be
31868            *     treated as an array of values.  If you specified a Type, the value will be
31869            *     treated as an array of the specified Type.  Note: query parameter values
31870            *     default to a special `"auto"` mode.
31871            *
31872            *     For query parameters in `"auto"` mode, if multiple  values for a single parameter
31873            *     are present in the URL (e.g.: `/foo?bar=1&bar=2&bar=3`) then the values
31874            *     are mapped to an array (e.g.: `{ foo: [ '1', '2', '3' ] }`).  However, if
31875            *     only one value is present (e.g.: `/foo?bar=1`) then the value is treated as single
31876            *     value (e.g.: `{ foo: '1' }`).
31877            *
31878            * <pre>params: {
31879            *     param1: { array: true }
31880            * }</pre>
31881            *
31882            *   - ** squash ** - {bool|string=}: `squash` configures how a default parameter value is represented in the URL when
31883            *     the current parameter value is the same as the default value. If `squash` is not set, it uses the
31884            *     configured default squash policy.
31885            *     (See {@link ui.router.util.$urlMatcherFactory#methods_defaultSquashPolicy `defaultSquashPolicy()`})
31886            *
31887            *   There are three squash settings:
31888            *
31889            *     - false: The parameter's default value is not squashed.  It is encoded and included in the URL
31890            *     - true: The parameter's default value is omitted from the URL.  If the parameter is preceeded and followed
31891            *       by slashes in the state's `url` declaration, then one of those slashes are omitted.
31892            *       This can allow for cleaner looking URLs.
31893            *     - `"<arbitrary string>"`: The parameter's default value is replaced with an arbitrary placeholder of  your choice.
31894            *
31895            * <pre>params: {
31896            *     param1: {
31897            *       value: "defaultId",
31898            *       squash: true
31899            * } }
31900            * // squash "defaultValue" to "~"
31901            * params: {
31902            *     param1: {
31903            *       value: "defaultValue",
31904            *       squash: "~"
31905            * } }
31906            * </pre>
31907            *
31908            *
31909            * @example
31910            * <pre>
31911            * // Some state name examples
31912            *
31913            * // stateName can be a single top-level name (must be unique).
31914            * $stateProvider.state("home", {});
31915            *
31916            * // Or it can be a nested state name. This state is a child of the
31917            * // above "home" state.
31918            * $stateProvider.state("home.newest", {});
31919            *
31920            * // Nest states as deeply as needed.
31921            * $stateProvider.state("home.newest.abc.xyz.inception", {});
31922            *
31923            * // state() returns $stateProvider, so you can chain state declarations.
31924            * $stateProvider
31925            *   .state("home", {})
31926            *   .state("about", {})
31927            *   .state("contacts", {});
31928            * </pre>
31929            *
31930            */
31931           this.state = state;
31932           function state(name, definition) {
31933             /*jshint validthis: true */
31934             if (isObject(name)) definition = name;
31935             else definition.name = name;
31936             registerState(definition);
31937             return this;
31938           }
31939
31940           /**
31941            * @ngdoc object
31942            * @name ui.router.state.$state
31943            *
31944            * @requires $rootScope
31945            * @requires $q
31946            * @requires ui.router.state.$view
31947            * @requires $injector
31948            * @requires ui.router.util.$resolve
31949            * @requires ui.router.state.$stateParams
31950            * @requires ui.router.router.$urlRouter
31951            *
31952            * @property {object} params A param object, e.g. {sectionId: section.id)}, that 
31953            * you'd like to test against the current active state.
31954            * @property {object} current A reference to the state's config object. However 
31955            * you passed it in. Useful for accessing custom data.
31956            * @property {object} transition Currently pending transition. A promise that'll 
31957            * resolve or reject.
31958            *
31959            * @description
31960            * `$state` service is responsible for representing states as well as transitioning
31961            * between them. It also provides interfaces to ask for current state or even states
31962            * you're coming from.
31963            */
31964           this.$get = $get;
31965           $get.$inject = ['$rootScope', '$q', '$view', '$injector', '$resolve', '$stateParams', '$urlRouter', '$location', '$urlMatcherFactory'];
31966           function $get(   $rootScope,   $q,   $view,   $injector,   $resolve,   $stateParams,   $urlRouter,   $location,   $urlMatcherFactory) {
31967
31968             var TransitionSuperseded = $q.reject(new Error('transition superseded'));
31969             var TransitionPrevented = $q.reject(new Error('transition prevented'));
31970             var TransitionAborted = $q.reject(new Error('transition aborted'));
31971             var TransitionFailed = $q.reject(new Error('transition failed'));
31972
31973             // Handles the case where a state which is the target of a transition is not found, and the user
31974             // can optionally retry or defer the transition
31975             function handleRedirect(redirect, state, params, options) {
31976               /**
31977                * @ngdoc event
31978                * @name ui.router.state.$state#$stateNotFound
31979                * @eventOf ui.router.state.$state
31980                * @eventType broadcast on root scope
31981                * @description
31982                * Fired when a requested state **cannot be found** using the provided state name during transition.
31983                * The event is broadcast allowing any handlers a single chance to deal with the error (usually by
31984                * lazy-loading the unfound state). A special `unfoundState` object is passed to the listener handler,
31985                * you can see its three properties in the example. You can use `event.preventDefault()` to abort the
31986                * transition and the promise returned from `go` will be rejected with a `'transition aborted'` value.
31987                *
31988                * @param {Object} event Event object.
31989                * @param {Object} unfoundState Unfound State information. Contains: `to, toParams, options` properties.
31990                * @param {State} fromState Current state object.
31991                * @param {Object} fromParams Current state params.
31992                *
31993                * @example
31994                *
31995                * <pre>
31996                * // somewhere, assume lazy.state has not been defined
31997                * $state.go("lazy.state", {a:1, b:2}, {inherit:false});
31998                *
31999                * // somewhere else
32000                * $scope.$on('$stateNotFound',
32001                * function(event, unfoundState, fromState, fromParams){
32002                *     console.log(unfoundState.to); // "lazy.state"
32003                *     console.log(unfoundState.toParams); // {a:1, b:2}
32004                *     console.log(unfoundState.options); // {inherit:false} + default options
32005                * })
32006                * </pre>
32007                */
32008               var evt = $rootScope.$broadcast('$stateNotFound', redirect, state, params);
32009
32010               if (evt.defaultPrevented) {
32011                 $urlRouter.update();
32012                 return TransitionAborted;
32013               }
32014
32015               if (!evt.retry) {
32016                 return null;
32017               }
32018
32019               // Allow the handler to return a promise to defer state lookup retry
32020               if (options.$retry) {
32021                 $urlRouter.update();
32022                 return TransitionFailed;
32023               }
32024               var retryTransition = $state.transition = $q.when(evt.retry);
32025
32026               retryTransition.then(function() {
32027                 if (retryTransition !== $state.transition) return TransitionSuperseded;
32028                 redirect.options.$retry = true;
32029                 return $state.transitionTo(redirect.to, redirect.toParams, redirect.options);
32030               }, function() {
32031                 return TransitionAborted;
32032               });
32033               $urlRouter.update();
32034
32035               return retryTransition;
32036             }
32037
32038             root.locals = { resolve: null, globals: { $stateParams: {} } };
32039
32040             $state = {
32041               params: {},
32042               current: root.self,
32043               $current: root,
32044               transition: null
32045             };
32046
32047             /**
32048              * @ngdoc function
32049              * @name ui.router.state.$state#reload
32050              * @methodOf ui.router.state.$state
32051              *
32052              * @description
32053              * A method that force reloads the current state. All resolves are re-resolved,
32054              * controllers reinstantiated, and events re-fired.
32055              *
32056              * @example
32057              * <pre>
32058              * var app angular.module('app', ['ui.router']);
32059              *
32060              * app.controller('ctrl', function ($scope, $state) {
32061              *   $scope.reload = function(){
32062              *     $state.reload();
32063              *   }
32064              * });
32065              * </pre>
32066              *
32067              * `reload()` is just an alias for:
32068              * <pre>
32069              * $state.transitionTo($state.current, $stateParams, { 
32070              *   reload: true, inherit: false, notify: true
32071              * });
32072              * </pre>
32073              *
32074              * @param {string=|object=} state - A state name or a state object, which is the root of the resolves to be re-resolved.
32075              * @example
32076              * <pre>
32077              * //assuming app application consists of 3 states: 'contacts', 'contacts.detail', 'contacts.detail.item' 
32078              * //and current state is 'contacts.detail.item'
32079              * var app angular.module('app', ['ui.router']);
32080              *
32081              * app.controller('ctrl', function ($scope, $state) {
32082              *   $scope.reload = function(){
32083              *     //will reload 'contact.detail' and 'contact.detail.item' states
32084              *     $state.reload('contact.detail');
32085              *   }
32086              * });
32087              * </pre>
32088              *
32089              * `reload()` is just an alias for:
32090              * <pre>
32091              * $state.transitionTo($state.current, $stateParams, { 
32092              *   reload: true, inherit: false, notify: true
32093              * });
32094              * </pre>
32095
32096              * @returns {promise} A promise representing the state of the new transition. See
32097              * {@link ui.router.state.$state#methods_go $state.go}.
32098              */
32099             $state.reload = function reload(state) {
32100               return $state.transitionTo($state.current, $stateParams, { reload: state || true, inherit: false, notify: true});
32101             };
32102
32103             /**
32104              * @ngdoc function
32105              * @name ui.router.state.$state#go
32106              * @methodOf ui.router.state.$state
32107              *
32108              * @description
32109              * Convenience method for transitioning to a new state. `$state.go` calls 
32110              * `$state.transitionTo` internally but automatically sets options to 
32111              * `{ location: true, inherit: true, relative: $state.$current, notify: true }`. 
32112              * This allows you to easily use an absolute or relative to path and specify 
32113              * only the parameters you'd like to update (while letting unspecified parameters 
32114              * inherit from the currently active ancestor states).
32115              *
32116              * @example
32117              * <pre>
32118              * var app = angular.module('app', ['ui.router']);
32119              *
32120              * app.controller('ctrl', function ($scope, $state) {
32121              *   $scope.changeState = function () {
32122              *     $state.go('contact.detail');
32123              *   };
32124              * });
32125              * </pre>
32126              * <img src='../ngdoc_assets/StateGoExamples.png'/>
32127              *
32128              * @param {string} to Absolute state name or relative state path. Some examples:
32129              *
32130              * - `$state.go('contact.detail')` - will go to the `contact.detail` state
32131              * - `$state.go('^')` - will go to a parent state
32132              * - `$state.go('^.sibling')` - will go to a sibling state
32133              * - `$state.go('.child.grandchild')` - will go to grandchild state
32134              *
32135              * @param {object=} params A map of the parameters that will be sent to the state, 
32136              * will populate $stateParams. Any parameters that are not specified will be inherited from currently 
32137              * defined parameters. This allows, for example, going to a sibling state that shares parameters
32138              * specified in a parent state. Parameter inheritance only works between common ancestor states, I.e.
32139              * transitioning to a sibling will get you the parameters for all parents, transitioning to a child
32140              * will get you all current parameters, etc.
32141              * @param {object=} options Options object. The options are:
32142              *
32143              * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
32144              *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
32145              * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
32146              * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
32147              *    defines which state to be relative from.
32148              * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
32149              * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params 
32150              *    have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
32151              *    use this when you want to force a reload when *everything* is the same, including search params.
32152              *
32153              * @returns {promise} A promise representing the state of the new transition.
32154              *
32155              * Possible success values:
32156              *
32157              * - $state.current
32158              *
32159              * <br/>Possible rejection values:
32160              *
32161              * - 'transition superseded' - when a newer transition has been started after this one
32162              * - 'transition prevented' - when `event.preventDefault()` has been called in a `$stateChangeStart` listener
32163              * - 'transition aborted' - when `event.preventDefault()` has been called in a `$stateNotFound` listener or
32164              *   when a `$stateNotFound` `event.retry` promise errors.
32165              * - 'transition failed' - when a state has been unsuccessfully found after 2 tries.
32166              * - *resolve error* - when an error has occurred with a `resolve`
32167              *
32168              */
32169             $state.go = function go(to, params, options) {
32170               return $state.transitionTo(to, params, extend({ inherit: true, relative: $state.$current }, options));
32171             };
32172
32173             /**
32174              * @ngdoc function
32175              * @name ui.router.state.$state#transitionTo
32176              * @methodOf ui.router.state.$state
32177              *
32178              * @description
32179              * Low-level method for transitioning to a new state. {@link ui.router.state.$state#methods_go $state.go}
32180              * uses `transitionTo` internally. `$state.go` is recommended in most situations.
32181              *
32182              * @example
32183              * <pre>
32184              * var app = angular.module('app', ['ui.router']);
32185              *
32186              * app.controller('ctrl', function ($scope, $state) {
32187              *   $scope.changeState = function () {
32188              *     $state.transitionTo('contact.detail');
32189              *   };
32190              * });
32191              * </pre>
32192              *
32193              * @param {string} to State name.
32194              * @param {object=} toParams A map of the parameters that will be sent to the state,
32195              * will populate $stateParams.
32196              * @param {object=} options Options object. The options are:
32197              *
32198              * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
32199              *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
32200              * - **`inherit`** - {boolean=false}, If `true` will inherit url parameters from current url.
32201              * - **`relative`** - {object=}, When transitioning with relative path (e.g '^'), 
32202              *    defines which state to be relative from.
32203              * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
32204              * - **`reload`** (v0.2.5) - {boolean=false|string=|object=}, If `true` will force transition even if the state or params 
32205              *    have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
32206              *    use this when you want to force a reload when *everything* is the same, including search params.
32207              *    if String, then will reload the state with the name given in reload, and any children.
32208              *    if Object, then a stateObj is expected, will reload the state found in stateObj, and any children.
32209              *
32210              * @returns {promise} A promise representing the state of the new transition. See
32211              * {@link ui.router.state.$state#methods_go $state.go}.
32212              */
32213             $state.transitionTo = function transitionTo(to, toParams, options) {
32214               toParams = toParams || {};
32215               options = extend({
32216                 location: true, inherit: false, relative: null, notify: true, reload: false, $retry: false
32217               }, options || {});
32218
32219               var from = $state.$current, fromParams = $state.params, fromPath = from.path;
32220               var evt, toState = findState(to, options.relative);
32221
32222               // Store the hash param for later (since it will be stripped out by various methods)
32223               var hash = toParams['#'];
32224
32225               if (!isDefined(toState)) {
32226                 var redirect = { to: to, toParams: toParams, options: options };
32227                 var redirectResult = handleRedirect(redirect, from.self, fromParams, options);
32228
32229                 if (redirectResult) {
32230                   return redirectResult;
32231                 }
32232
32233                 // Always retry once if the $stateNotFound was not prevented
32234                 // (handles either redirect changed or state lazy-definition)
32235                 to = redirect.to;
32236                 toParams = redirect.toParams;
32237                 options = redirect.options;
32238                 toState = findState(to, options.relative);
32239
32240                 if (!isDefined(toState)) {
32241                   if (!options.relative) throw new Error("No such state '" + to + "'");
32242                   throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'");
32243                 }
32244               }
32245               if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
32246               if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState);
32247               if (!toState.params.$$validates(toParams)) return TransitionFailed;
32248
32249               toParams = toState.params.$$values(toParams);
32250               to = toState;
32251
32252               var toPath = to.path;
32253
32254               // Starting from the root of the path, keep all levels that haven't changed
32255               var keep = 0, state = toPath[keep], locals = root.locals, toLocals = [];
32256
32257               if (!options.reload) {
32258                 while (state && state === fromPath[keep] && state.ownParams.$$equals(toParams, fromParams)) {
32259                   locals = toLocals[keep] = state.locals;
32260                   keep++;
32261                   state = toPath[keep];
32262                 }
32263               } else if (isString(options.reload) || isObject(options.reload)) {
32264                 if (isObject(options.reload) && !options.reload.name) {
32265                   throw new Error('Invalid reload state object');
32266                 }
32267                 
32268                 var reloadState = options.reload === true ? fromPath[0] : findState(options.reload);
32269                 if (options.reload && !reloadState) {
32270                   throw new Error("No such reload state '" + (isString(options.reload) ? options.reload : options.reload.name) + "'");
32271                 }
32272
32273                 while (state && state === fromPath[keep] && state !== reloadState) {
32274                   locals = toLocals[keep] = state.locals;
32275                   keep++;
32276                   state = toPath[keep];
32277                 }
32278               }
32279
32280               // If we're going to the same state and all locals are kept, we've got nothing to do.
32281               // But clear 'transition', as we still want to cancel any other pending transitions.
32282               // TODO: We may not want to bump 'transition' if we're called from a location change
32283               // that we've initiated ourselves, because we might accidentally abort a legitimate
32284               // transition initiated from code?
32285               if (shouldSkipReload(to, toParams, from, fromParams, locals, options)) {
32286                 if (hash) toParams['#'] = hash;
32287                 $state.params = toParams;
32288                 copy($state.params, $stateParams);
32289                 if (options.location && to.navigable && to.navigable.url) {
32290                   $urlRouter.push(to.navigable.url, toParams, {
32291                     $$avoidResync: true, replace: options.location === 'replace'
32292                   });
32293                   $urlRouter.update(true);
32294                 }
32295                 $state.transition = null;
32296                 return $q.when($state.current);
32297               }
32298
32299               // Filter parameters before we pass them to event handlers etc.
32300               toParams = filterByKeys(to.params.$$keys(), toParams || {});
32301
32302               // Broadcast start event and cancel the transition if requested
32303               if (options.notify) {
32304                 /**
32305                  * @ngdoc event
32306                  * @name ui.router.state.$state#$stateChangeStart
32307                  * @eventOf ui.router.state.$state
32308                  * @eventType broadcast on root scope
32309                  * @description
32310                  * Fired when the state transition **begins**. You can use `event.preventDefault()`
32311                  * to prevent the transition from happening and then the transition promise will be
32312                  * rejected with a `'transition prevented'` value.
32313                  *
32314                  * @param {Object} event Event object.
32315                  * @param {State} toState The state being transitioned to.
32316                  * @param {Object} toParams The params supplied to the `toState`.
32317                  * @param {State} fromState The current state, pre-transition.
32318                  * @param {Object} fromParams The params supplied to the `fromState`.
32319                  *
32320                  * @example
32321                  *
32322                  * <pre>
32323                  * $rootScope.$on('$stateChangeStart',
32324                  * function(event, toState, toParams, fromState, fromParams){
32325                  *     event.preventDefault();
32326                  *     // transitionTo() promise will be rejected with
32327                  *     // a 'transition prevented' error
32328                  * })
32329                  * </pre>
32330                  */
32331                 if ($rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams).defaultPrevented) {
32332                   $rootScope.$broadcast('$stateChangeCancel', to.self, toParams, from.self, fromParams);
32333                   $urlRouter.update();
32334                   return TransitionPrevented;
32335                 }
32336               }
32337
32338               // Resolve locals for the remaining states, but don't update any global state just
32339               // yet -- if anything fails to resolve the current state needs to remain untouched.
32340               // We also set up an inheritance chain for the locals here. This allows the view directive
32341               // to quickly look up the correct definition for each view in the current state. Even
32342               // though we create the locals object itself outside resolveState(), it is initially
32343               // empty and gets filled asynchronously. We need to keep track of the promise for the
32344               // (fully resolved) current locals, and pass this down the chain.
32345               var resolved = $q.when(locals);
32346
32347               for (var l = keep; l < toPath.length; l++, state = toPath[l]) {
32348                 locals = toLocals[l] = inherit(locals);
32349                 resolved = resolveState(state, toParams, state === to, resolved, locals, options);
32350               }
32351
32352               // Once everything is resolved, we are ready to perform the actual transition
32353               // and return a promise for the new state. We also keep track of what the
32354               // current promise is, so that we can detect overlapping transitions and
32355               // keep only the outcome of the last transition.
32356               var transition = $state.transition = resolved.then(function () {
32357                 var l, entering, exiting;
32358
32359                 if ($state.transition !== transition) return TransitionSuperseded;
32360
32361                 // Exit 'from' states not kept
32362                 for (l = fromPath.length - 1; l >= keep; l--) {
32363                   exiting = fromPath[l];
32364                   if (exiting.self.onExit) {
32365                     $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals);
32366                   }
32367                   exiting.locals = null;
32368                 }
32369
32370                 // Enter 'to' states not kept
32371                 for (l = keep; l < toPath.length; l++) {
32372                   entering = toPath[l];
32373                   entering.locals = toLocals[l];
32374                   if (entering.self.onEnter) {
32375                     $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
32376                   }
32377                 }
32378
32379                 // Re-add the saved hash before we start returning things
32380                 if (hash) toParams['#'] = hash;
32381
32382                 // Run it again, to catch any transitions in callbacks
32383                 if ($state.transition !== transition) return TransitionSuperseded;
32384
32385                 // Update globals in $state
32386                 $state.$current = to;
32387                 $state.current = to.self;
32388                 $state.params = toParams;
32389                 copy($state.params, $stateParams);
32390                 $state.transition = null;
32391
32392                 if (options.location && to.navigable) {
32393                   $urlRouter.push(to.navigable.url, to.navigable.locals.globals.$stateParams, {
32394                     $$avoidResync: true, replace: options.location === 'replace'
32395                   });
32396                 }
32397
32398                 if (options.notify) {
32399                 /**
32400                  * @ngdoc event
32401                  * @name ui.router.state.$state#$stateChangeSuccess
32402                  * @eventOf ui.router.state.$state
32403                  * @eventType broadcast on root scope
32404                  * @description
32405                  * Fired once the state transition is **complete**.
32406                  *
32407                  * @param {Object} event Event object.
32408                  * @param {State} toState The state being transitioned to.
32409                  * @param {Object} toParams The params supplied to the `toState`.
32410                  * @param {State} fromState The current state, pre-transition.
32411                  * @param {Object} fromParams The params supplied to the `fromState`.
32412                  */
32413                   $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams);
32414                 }
32415                 $urlRouter.update(true);
32416
32417                 return $state.current;
32418               }, function (error) {
32419                 if ($state.transition !== transition) return TransitionSuperseded;
32420
32421                 $state.transition = null;
32422                 /**
32423                  * @ngdoc event
32424                  * @name ui.router.state.$state#$stateChangeError
32425                  * @eventOf ui.router.state.$state
32426                  * @eventType broadcast on root scope
32427                  * @description
32428                  * Fired when an **error occurs** during transition. It's important to note that if you
32429                  * have any errors in your resolve functions (javascript errors, non-existent services, etc)
32430                  * they will not throw traditionally. You must listen for this $stateChangeError event to
32431                  * catch **ALL** errors.
32432                  *
32433                  * @param {Object} event Event object.
32434                  * @param {State} toState The state being transitioned to.
32435                  * @param {Object} toParams The params supplied to the `toState`.
32436                  * @param {State} fromState The current state, pre-transition.
32437                  * @param {Object} fromParams The params supplied to the `fromState`.
32438                  * @param {Error} error The resolve error object.
32439                  */
32440                 evt = $rootScope.$broadcast('$stateChangeError', to.self, toParams, from.self, fromParams, error);
32441
32442                 if (!evt.defaultPrevented) {
32443                     $urlRouter.update();
32444                 }
32445
32446                 return $q.reject(error);
32447               });
32448
32449               return transition;
32450             };
32451
32452             /**
32453              * @ngdoc function
32454              * @name ui.router.state.$state#is
32455              * @methodOf ui.router.state.$state
32456              *
32457              * @description
32458              * Similar to {@link ui.router.state.$state#methods_includes $state.includes},
32459              * but only checks for the full state name. If params is supplied then it will be
32460              * tested for strict equality against the current active params object, so all params
32461              * must match with none missing and no extras.
32462              *
32463              * @example
32464              * <pre>
32465              * $state.$current.name = 'contacts.details.item';
32466              *
32467              * // absolute name
32468              * $state.is('contact.details.item'); // returns true
32469              * $state.is(contactDetailItemStateObject); // returns true
32470              *
32471              * // relative name (. and ^), typically from a template
32472              * // E.g. from the 'contacts.details' template
32473              * <div ng-class="{highlighted: $state.is('.item')}">Item</div>
32474              * </pre>
32475              *
32476              * @param {string|object} stateOrName The state name (absolute or relative) or state object you'd like to check.
32477              * @param {object=} params A param object, e.g. `{sectionId: section.id}`, that you'd like
32478              * to test against the current active state.
32479              * @param {object=} options An options object.  The options are:
32480              *
32481              * - **`relative`** - {string|object} -  If `stateOrName` is a relative state name and `options.relative` is set, .is will
32482              * test relative to `options.relative` state (or name).
32483              *
32484              * @returns {boolean} Returns true if it is the state.
32485              */
32486             $state.is = function is(stateOrName, params, options) {
32487               options = extend({ relative: $state.$current }, options || {});
32488               var state = findState(stateOrName, options.relative);
32489
32490               if (!isDefined(state)) { return undefined; }
32491               if ($state.$current !== state) { return false; }
32492               return params ? equalForKeys(state.params.$$values(params), $stateParams) : true;
32493             };
32494
32495             /**
32496              * @ngdoc function
32497              * @name ui.router.state.$state#includes
32498              * @methodOf ui.router.state.$state
32499              *
32500              * @description
32501              * A method to determine if the current active state is equal to or is the child of the
32502              * state stateName. If any params are passed then they will be tested for a match as well.
32503              * Not all the parameters need to be passed, just the ones you'd like to test for equality.
32504              *
32505              * @example
32506              * Partial and relative names
32507              * <pre>
32508              * $state.$current.name = 'contacts.details.item';
32509              *
32510              * // Using partial names
32511              * $state.includes("contacts"); // returns true
32512              * $state.includes("contacts.details"); // returns true
32513              * $state.includes("contacts.details.item"); // returns true
32514              * $state.includes("contacts.list"); // returns false
32515              * $state.includes("about"); // returns false
32516              *
32517              * // Using relative names (. and ^), typically from a template
32518              * // E.g. from the 'contacts.details' template
32519              * <div ng-class="{highlighted: $state.includes('.item')}">Item</div>
32520              * </pre>
32521              *
32522              * Basic globbing patterns
32523              * <pre>
32524              * $state.$current.name = 'contacts.details.item.url';
32525              *
32526              * $state.includes("*.details.*.*"); // returns true
32527              * $state.includes("*.details.**"); // returns true
32528              * $state.includes("**.item.**"); // returns true
32529              * $state.includes("*.details.item.url"); // returns true
32530              * $state.includes("*.details.*.url"); // returns true
32531              * $state.includes("*.details.*"); // returns false
32532              * $state.includes("item.**"); // returns false
32533              * </pre>
32534              *
32535              * @param {string} stateOrName A partial name, relative name, or glob pattern
32536              * to be searched for within the current state name.
32537              * @param {object=} params A param object, e.g. `{sectionId: section.id}`,
32538              * that you'd like to test against the current active state.
32539              * @param {object=} options An options object.  The options are:
32540              *
32541              * - **`relative`** - {string|object=} -  If `stateOrName` is a relative state reference and `options.relative` is set,
32542              * .includes will test relative to `options.relative` state (or name).
32543              *
32544              * @returns {boolean} Returns true if it does include the state
32545              */
32546             $state.includes = function includes(stateOrName, params, options) {
32547               options = extend({ relative: $state.$current }, options || {});
32548               if (isString(stateOrName) && isGlob(stateOrName)) {
32549                 if (!doesStateMatchGlob(stateOrName)) {
32550                   return false;
32551                 }
32552                 stateOrName = $state.$current.name;
32553               }
32554
32555               var state = findState(stateOrName, options.relative);
32556               if (!isDefined(state)) { return undefined; }
32557               if (!isDefined($state.$current.includes[state.name])) { return false; }
32558               return params ? equalForKeys(state.params.$$values(params), $stateParams, objectKeys(params)) : true;
32559             };
32560
32561
32562             /**
32563              * @ngdoc function
32564              * @name ui.router.state.$state#href
32565              * @methodOf ui.router.state.$state
32566              *
32567              * @description
32568              * A url generation method that returns the compiled url for the given state populated with the given params.
32569              *
32570              * @example
32571              * <pre>
32572              * expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
32573              * </pre>
32574              *
32575              * @param {string|object} stateOrName The state name or state object you'd like to generate a url from.
32576              * @param {object=} params An object of parameter values to fill the state's required parameters.
32577              * @param {object=} options Options object. The options are:
32578              *
32579              * - **`lossy`** - {boolean=true} -  If true, and if there is no url associated with the state provided in the
32580              *    first parameter, then the constructed href url will be built from the first navigable ancestor (aka
32581              *    ancestor with a valid url).
32582              * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
32583              * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
32584              *    defines which state to be relative from.
32585              * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
32586              * 
32587              * @returns {string} compiled state url
32588              */
32589             $state.href = function href(stateOrName, params, options) {
32590               options = extend({
32591                 lossy:    true,
32592                 inherit:  true,
32593                 absolute: false,
32594                 relative: $state.$current
32595               }, options || {});
32596
32597               var state = findState(stateOrName, options.relative);
32598
32599               if (!isDefined(state)) return null;
32600               if (options.inherit) params = inheritParams($stateParams, params || {}, $state.$current, state);
32601               
32602               var nav = (state && options.lossy) ? state.navigable : state;
32603
32604               if (!nav || nav.url === undefined || nav.url === null) {
32605                 return null;
32606               }
32607               return $urlRouter.href(nav.url, filterByKeys(state.params.$$keys().concat('#'), params || {}), {
32608                 absolute: options.absolute
32609               });
32610             };
32611
32612             /**
32613              * @ngdoc function
32614              * @name ui.router.state.$state#get
32615              * @methodOf ui.router.state.$state
32616              *
32617              * @description
32618              * Returns the state configuration object for any specific state or all states.
32619              *
32620              * @param {string|object=} stateOrName (absolute or relative) If provided, will only get the config for
32621              * the requested state. If not provided, returns an array of ALL state configs.
32622              * @param {string|object=} context When stateOrName is a relative state reference, the state will be retrieved relative to context.
32623              * @returns {Object|Array} State configuration object or array of all objects.
32624              */
32625             $state.get = function (stateOrName, context) {
32626               if (arguments.length === 0) return map(objectKeys(states), function(name) { return states[name].self; });
32627               var state = findState(stateOrName, context || $state.$current);
32628               return (state && state.self) ? state.self : null;
32629             };
32630
32631             function resolveState(state, params, paramsAreFiltered, inherited, dst, options) {
32632               // Make a restricted $stateParams with only the parameters that apply to this state if
32633               // necessary. In addition to being available to the controller and onEnter/onExit callbacks,
32634               // we also need $stateParams to be available for any $injector calls we make during the
32635               // dependency resolution process.
32636               var $stateParams = (paramsAreFiltered) ? params : filterByKeys(state.params.$$keys(), params);
32637               var locals = { $stateParams: $stateParams };
32638
32639               // Resolve 'global' dependencies for the state, i.e. those not specific to a view.
32640               // We're also including $stateParams in this; that way the parameters are restricted
32641               // to the set that should be visible to the state, and are independent of when we update
32642               // the global $state and $stateParams values.
32643               dst.resolve = $resolve.resolve(state.resolve, locals, dst.resolve, state);
32644               var promises = [dst.resolve.then(function (globals) {
32645                 dst.globals = globals;
32646               })];
32647               if (inherited) promises.push(inherited);
32648
32649               function resolveViews() {
32650                 var viewsPromises = [];
32651
32652                 // Resolve template and dependencies for all views.
32653                 forEach(state.views, function (view, name) {
32654                   var injectables = (view.resolve && view.resolve !== state.resolve ? view.resolve : {});
32655                   injectables.$template = [ function () {
32656                     return $view.load(name, { view: view, locals: dst.globals, params: $stateParams, notify: options.notify }) || '';
32657                   }];
32658
32659                   viewsPromises.push($resolve.resolve(injectables, dst.globals, dst.resolve, state).then(function (result) {
32660                     // References to the controller (only instantiated at link time)
32661                     if (isFunction(view.controllerProvider) || isArray(view.controllerProvider)) {
32662                       var injectLocals = angular.extend({}, injectables, dst.globals);
32663                       result.$$controller = $injector.invoke(view.controllerProvider, null, injectLocals);
32664                     } else {
32665                       result.$$controller = view.controller;
32666                     }
32667                     // Provide access to the state itself for internal use
32668                     result.$$state = state;
32669                     result.$$controllerAs = view.controllerAs;
32670                     dst[name] = result;
32671                   }));
32672                 });
32673
32674                 return $q.all(viewsPromises).then(function(){
32675                   return dst.globals;
32676                 });
32677               }
32678
32679               // Wait for all the promises and then return the activation object
32680               return $q.all(promises).then(resolveViews).then(function (values) {
32681                 return dst;
32682               });
32683             }
32684
32685             return $state;
32686           }
32687
32688           function shouldSkipReload(to, toParams, from, fromParams, locals, options) {
32689             // Return true if there are no differences in non-search (path/object) params, false if there are differences
32690             function nonSearchParamsEqual(fromAndToState, fromParams, toParams) {
32691               // Identify whether all the parameters that differ between `fromParams` and `toParams` were search params.
32692               function notSearchParam(key) {
32693                 return fromAndToState.params[key].location != "search";
32694               }
32695               var nonQueryParamKeys = fromAndToState.params.$$keys().filter(notSearchParam);
32696               var nonQueryParams = pick.apply({}, [fromAndToState.params].concat(nonQueryParamKeys));
32697               var nonQueryParamSet = new $$UMFP.ParamSet(nonQueryParams);
32698               return nonQueryParamSet.$$equals(fromParams, toParams);
32699             }
32700
32701             // If reload was not explicitly requested
32702             // and we're transitioning to the same state we're already in
32703             // and    the locals didn't change
32704             //     or they changed in a way that doesn't merit reloading
32705             //        (reloadOnParams:false, or reloadOnSearch.false and only search params changed)
32706             // Then return true.
32707             if (!options.reload && to === from &&
32708               (locals === from.locals || (to.self.reloadOnSearch === false && nonSearchParamsEqual(from, fromParams, toParams)))) {
32709               return true;
32710             }
32711           }
32712         }
32713
32714         angular.module('ui.router.state')
32715           .value('$stateParams', {})
32716           .provider('$state', $StateProvider);
32717
32718
32719         $ViewProvider.$inject = [];
32720         function $ViewProvider() {
32721
32722           this.$get = $get;
32723           /**
32724            * @ngdoc object
32725            * @name ui.router.state.$view
32726            *
32727            * @requires ui.router.util.$templateFactory
32728            * @requires $rootScope
32729            *
32730            * @description
32731            *
32732            */
32733           $get.$inject = ['$rootScope', '$templateFactory'];
32734           function $get(   $rootScope,   $templateFactory) {
32735             return {
32736               // $view.load('full.viewName', { template: ..., controller: ..., resolve: ..., async: false, params: ... })
32737               /**
32738                * @ngdoc function
32739                * @name ui.router.state.$view#load
32740                * @methodOf ui.router.state.$view
32741                *
32742                * @description
32743                *
32744                * @param {string} name name
32745                * @param {object} options option object.
32746                */
32747               load: function load(name, options) {
32748                 var result, defaults = {
32749                   template: null, controller: null, view: null, locals: null, notify: true, async: true, params: {}
32750                 };
32751                 options = extend(defaults, options);
32752
32753                 if (options.view) {
32754                   result = $templateFactory.fromConfig(options.view, options.params, options.locals);
32755                 }
32756                 if (result && options.notify) {
32757                 /**
32758                  * @ngdoc event
32759                  * @name ui.router.state.$state#$viewContentLoading
32760                  * @eventOf ui.router.state.$view
32761                  * @eventType broadcast on root scope
32762                  * @description
32763                  *
32764                  * Fired once the view **begins loading**, *before* the DOM is rendered.
32765                  *
32766                  * @param {Object} event Event object.
32767                  * @param {Object} viewConfig The view config properties (template, controller, etc).
32768                  *
32769                  * @example
32770                  *
32771                  * <pre>
32772                  * $scope.$on('$viewContentLoading',
32773                  * function(event, viewConfig){
32774                  *     // Access to all the view config properties.
32775                  *     // and one special property 'targetView'
32776                  *     // viewConfig.targetView
32777                  * });
32778                  * </pre>
32779                  */
32780                   $rootScope.$broadcast('$viewContentLoading', options);
32781                 }
32782                 return result;
32783               }
32784             };
32785           }
32786         }
32787
32788         angular.module('ui.router.state').provider('$view', $ViewProvider);
32789
32790         /**
32791          * @ngdoc object
32792          * @name ui.router.state.$uiViewScrollProvider
32793          *
32794          * @description
32795          * Provider that returns the {@link ui.router.state.$uiViewScroll} service function.
32796          */
32797         function $ViewScrollProvider() {
32798
32799           var useAnchorScroll = false;
32800
32801           /**
32802            * @ngdoc function
32803            * @name ui.router.state.$uiViewScrollProvider#useAnchorScroll
32804            * @methodOf ui.router.state.$uiViewScrollProvider
32805            *
32806            * @description
32807            * Reverts back to using the core [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) service for
32808            * scrolling based on the url anchor.
32809            */
32810           this.useAnchorScroll = function () {
32811             useAnchorScroll = true;
32812           };
32813
32814           /**
32815            * @ngdoc object
32816            * @name ui.router.state.$uiViewScroll
32817            *
32818            * @requires $anchorScroll
32819            * @requires $timeout
32820            *
32821            * @description
32822            * When called with a jqLite element, it scrolls the element into view (after a
32823            * `$timeout` so the DOM has time to refresh).
32824            *
32825            * If you prefer to rely on `$anchorScroll` to scroll the view to the anchor,
32826            * this can be enabled by calling {@link ui.router.state.$uiViewScrollProvider#methods_useAnchorScroll `$uiViewScrollProvider.useAnchorScroll()`}.
32827            */
32828           this.$get = ['$anchorScroll', '$timeout', function ($anchorScroll, $timeout) {
32829             if (useAnchorScroll) {
32830               return $anchorScroll;
32831             }
32832
32833             return function ($element) {
32834               return $timeout(function () {
32835                 $element[0].scrollIntoView();
32836               }, 0, false);
32837             };
32838           }];
32839         }
32840
32841         angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider);
32842
32843         /**
32844          * @ngdoc directive
32845          * @name ui.router.state.directive:ui-view
32846          *
32847          * @requires ui.router.state.$state
32848          * @requires $compile
32849          * @requires $controller
32850          * @requires $injector
32851          * @requires ui.router.state.$uiViewScroll
32852          * @requires $document
32853          *
32854          * @restrict ECA
32855          *
32856          * @description
32857          * The ui-view directive tells $state where to place your templates.
32858          *
32859          * @param {string=} name A view name. The name should be unique amongst the other views in the
32860          * same state. You can have views of the same name that live in different states.
32861          *
32862          * @param {string=} autoscroll It allows you to set the scroll behavior of the browser window
32863          * when a view is populated. By default, $anchorScroll is overridden by ui-router's custom scroll
32864          * service, {@link ui.router.state.$uiViewScroll}. This custom service let's you
32865          * scroll ui-view elements into view when they are populated during a state activation.
32866          *
32867          * *Note: To revert back to old [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll)
32868          * functionality, call `$uiViewScrollProvider.useAnchorScroll()`.*
32869          *
32870          * @param {string=} onload Expression to evaluate whenever the view updates.
32871          * 
32872          * @example
32873          * A view can be unnamed or named. 
32874          * <pre>
32875          * <!-- Unnamed -->
32876          * <div ui-view></div> 
32877          * 
32878          * <!-- Named -->
32879          * <div ui-view="viewName"></div>
32880          * </pre>
32881          *
32882          * You can only have one unnamed view within any template (or root html). If you are only using a 
32883          * single view and it is unnamed then you can populate it like so:
32884          * <pre>
32885          * <div ui-view></div> 
32886          * $stateProvider.state("home", {
32887          *   template: "<h1>HELLO!</h1>"
32888          * })
32889          * </pre>
32890          * 
32891          * The above is a convenient shortcut equivalent to specifying your view explicitly with the {@link ui.router.state.$stateProvider#views `views`}
32892          * config property, by name, in this case an empty name:
32893          * <pre>
32894          * $stateProvider.state("home", {
32895          *   views: {
32896          *     "": {
32897          *       template: "<h1>HELLO!</h1>"
32898          *     }
32899          *   }    
32900          * })
32901          * </pre>
32902          * 
32903          * But typically you'll only use the views property if you name your view or have more than one view 
32904          * in the same template. There's not really a compelling reason to name a view if its the only one, 
32905          * but you could if you wanted, like so:
32906          * <pre>
32907          * <div ui-view="main"></div>
32908          * </pre> 
32909          * <pre>
32910          * $stateProvider.state("home", {
32911          *   views: {
32912          *     "main": {
32913          *       template: "<h1>HELLO!</h1>"
32914          *     }
32915          *   }    
32916          * })
32917          * </pre>
32918          * 
32919          * Really though, you'll use views to set up multiple views:
32920          * <pre>
32921          * <div ui-view></div>
32922          * <div ui-view="chart"></div> 
32923          * <div ui-view="data"></div> 
32924          * </pre>
32925          * 
32926          * <pre>
32927          * $stateProvider.state("home", {
32928          *   views: {
32929          *     "": {
32930          *       template: "<h1>HELLO!</h1>"
32931          *     },
32932          *     "chart": {
32933          *       template: "<chart_thing/>"
32934          *     },
32935          *     "data": {
32936          *       template: "<data_thing/>"
32937          *     }
32938          *   }    
32939          * })
32940          * </pre>
32941          *
32942          * Examples for `autoscroll`:
32943          *
32944          * <pre>
32945          * <!-- If autoscroll present with no expression,
32946          *      then scroll ui-view into view -->
32947          * <ui-view autoscroll/>
32948          *
32949          * <!-- If autoscroll present with valid expression,
32950          *      then scroll ui-view into view if expression evaluates to true -->
32951          * <ui-view autoscroll='true'/>
32952          * <ui-view autoscroll='false'/>
32953          * <ui-view autoscroll='scopeVariable'/>
32954          * </pre>
32955          */
32956         $ViewDirective.$inject = ['$state', '$injector', '$uiViewScroll', '$interpolate'];
32957         function $ViewDirective(   $state,   $injector,   $uiViewScroll,   $interpolate) {
32958
32959           function getService() {
32960             return ($injector.has) ? function(service) {
32961               return $injector.has(service) ? $injector.get(service) : null;
32962             } : function(service) {
32963               try {
32964                 return $injector.get(service);
32965               } catch (e) {
32966                 return null;
32967               }
32968             };
32969           }
32970
32971           var service = getService(),
32972               $animator = service('$animator'),
32973               $animate = service('$animate');
32974
32975           // Returns a set of DOM manipulation functions based on which Angular version
32976           // it should use
32977           function getRenderer(attrs, scope) {
32978             var statics = function() {
32979               return {
32980                 enter: function (element, target, cb) { target.after(element); cb(); },
32981                 leave: function (element, cb) { element.remove(); cb(); }
32982               };
32983             };
32984
32985             if ($animate) {
32986               return {
32987                 enter: function(element, target, cb) {
32988                   var promise = $animate.enter(element, null, target, cb);
32989                   if (promise && promise.then) promise.then(cb);
32990                 },
32991                 leave: function(element, cb) {
32992                   var promise = $animate.leave(element, cb);
32993                   if (promise && promise.then) promise.then(cb);
32994                 }
32995               };
32996             }
32997
32998             if ($animator) {
32999               var animate = $animator && $animator(scope, attrs);
33000
33001               return {
33002                 enter: function(element, target, cb) {animate.enter(element, null, target); cb(); },
33003                 leave: function(element, cb) { animate.leave(element); cb(); }
33004               };
33005             }
33006
33007             return statics();
33008           }
33009
33010           var directive = {
33011             restrict: 'ECA',
33012             terminal: true,
33013             priority: 400,
33014             transclude: 'element',
33015             compile: function (tElement, tAttrs, $transclude) {
33016               return function (scope, $element, attrs) {
33017                 var previousEl, currentEl, currentScope, latestLocals,
33018                     onloadExp     = attrs.onload || '',
33019                     autoScrollExp = attrs.autoscroll,
33020                     renderer      = getRenderer(attrs, scope);
33021
33022                 scope.$on('$stateChangeSuccess', function() {
33023                   updateView(false);
33024                 });
33025                 scope.$on('$viewContentLoading', function() {
33026                   updateView(false);
33027                 });
33028
33029                 updateView(true);
33030
33031                 function cleanupLastView() {
33032                   if (previousEl) {
33033                     previousEl.remove();
33034                     previousEl = null;
33035                   }
33036
33037                   if (currentScope) {
33038                     currentScope.$destroy();
33039                     currentScope = null;
33040                   }
33041
33042                   if (currentEl) {
33043                     renderer.leave(currentEl, function() {
33044                       previousEl = null;
33045                     });
33046
33047                     previousEl = currentEl;
33048                     currentEl = null;
33049                   }
33050                 }
33051
33052                 function updateView(firstTime) {
33053                   var newScope,
33054                       name            = getUiViewName(scope, attrs, $element, $interpolate),
33055                       previousLocals  = name && $state.$current && $state.$current.locals[name];
33056
33057                   if (!firstTime && previousLocals === latestLocals) return; // nothing to do
33058                   newScope = scope.$new();
33059                   latestLocals = $state.$current.locals[name];
33060
33061                   var clone = $transclude(newScope, function(clone) {
33062                     renderer.enter(clone, $element, function onUiViewEnter() {
33063                       if(currentScope) {
33064                         currentScope.$emit('$viewContentAnimationEnded');
33065                       }
33066
33067                       if (angular.isDefined(autoScrollExp) && !autoScrollExp || scope.$eval(autoScrollExp)) {
33068                         $uiViewScroll(clone);
33069                       }
33070                     });
33071                     cleanupLastView();
33072                   });
33073
33074                   currentEl = clone;
33075                   currentScope = newScope;
33076                   /**
33077                    * @ngdoc event
33078                    * @name ui.router.state.directive:ui-view#$viewContentLoaded
33079                    * @eventOf ui.router.state.directive:ui-view
33080                    * @eventType emits on ui-view directive scope
33081                    * @description           *
33082                    * Fired once the view is **loaded**, *after* the DOM is rendered.
33083                    *
33084                    * @param {Object} event Event object.
33085                    */
33086                   currentScope.$emit('$viewContentLoaded');
33087                   currentScope.$eval(onloadExp);
33088                 }
33089               };
33090             }
33091           };
33092
33093           return directive;
33094         }
33095
33096         $ViewDirectiveFill.$inject = ['$compile', '$controller', '$state', '$interpolate'];
33097         function $ViewDirectiveFill (  $compile,   $controller,   $state,   $interpolate) {
33098           return {
33099             restrict: 'ECA',
33100             priority: -400,
33101             compile: function (tElement) {
33102               var initial = tElement.html();
33103               return function (scope, $element, attrs) {
33104                 var current = $state.$current,
33105                     name = getUiViewName(scope, attrs, $element, $interpolate),
33106                     locals  = current && current.locals[name];
33107
33108                 if (! locals) {
33109                   return;
33110                 }
33111
33112                 $element.data('$uiView', { name: name, state: locals.$$state });
33113                 $element.html(locals.$template ? locals.$template : initial);
33114
33115                 var link = $compile($element.contents());
33116
33117                 if (locals.$$controller) {
33118                   locals.$scope = scope;
33119                   locals.$element = $element;
33120                   var controller = $controller(locals.$$controller, locals);
33121                   if (locals.$$controllerAs) {
33122                     scope[locals.$$controllerAs] = controller;
33123                   }
33124                   $element.data('$ngControllerController', controller);
33125                   $element.children().data('$ngControllerController', controller);
33126                 }
33127
33128                 link(scope);
33129               };
33130             }
33131           };
33132         }
33133
33134         /**
33135          * Shared ui-view code for both directives:
33136          * Given scope, element, and its attributes, return the view's name
33137          */
33138         function getUiViewName(scope, attrs, element, $interpolate) {
33139           var name = $interpolate(attrs.uiView || attrs.name || '')(scope);
33140           var inherited = element.inheritedData('$uiView');
33141           return name.indexOf('@') >= 0 ?  name :  (name + '@' + (inherited ? inherited.state.name : ''));
33142         }
33143
33144         angular.module('ui.router.state').directive('uiView', $ViewDirective);
33145         angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill);
33146
33147         function parseStateRef(ref, current) {
33148           var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed;
33149           if (preparsed) ref = current + '(' + preparsed[1] + ')';
33150           parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
33151           if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'");
33152           return { state: parsed[1], paramExpr: parsed[3] || null };
33153         }
33154
33155         function stateContext(el) {
33156           var stateData = el.parent().inheritedData('$uiView');
33157
33158           if (stateData && stateData.state && stateData.state.name) {
33159             return stateData.state;
33160           }
33161         }
33162
33163         /**
33164          * @ngdoc directive
33165          * @name ui.router.state.directive:ui-sref
33166          *
33167          * @requires ui.router.state.$state
33168          * @requires $timeout
33169          *
33170          * @restrict A
33171          *
33172          * @description
33173          * A directive that binds a link (`<a>` tag) to a state. If the state has an associated 
33174          * URL, the directive will automatically generate & update the `href` attribute via 
33175          * the {@link ui.router.state.$state#methods_href $state.href()} method. Clicking 
33176          * the link will trigger a state transition with optional parameters. 
33177          *
33178          * Also middle-clicking, right-clicking, and ctrl-clicking on the link will be 
33179          * handled natively by the browser.
33180          *
33181          * You can also use relative state paths within ui-sref, just like the relative 
33182          * paths passed to `$state.go()`. You just need to be aware that the path is relative
33183          * to the state that the link lives in, in other words the state that loaded the 
33184          * template containing the link.
33185          *
33186          * You can specify options to pass to {@link ui.router.state.$state#go $state.go()}
33187          * using the `ui-sref-opts` attribute. Options are restricted to `location`, `inherit`,
33188          * and `reload`.
33189          *
33190          * @example
33191          * Here's an example of how you'd use ui-sref and how it would compile. If you have the 
33192          * following template:
33193          * <pre>
33194          * <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> | <a ui-sref="{page: 2}">Next page</a>
33195          * 
33196          * <ul>
33197          *     <li ng-repeat="contact in contacts">
33198          *         <a ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a>
33199          *     </li>
33200          * </ul>
33201          * </pre>
33202          * 
33203          * Then the compiled html would be (assuming Html5Mode is off and current state is contacts):
33204          * <pre>
33205          * <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>
33206          * 
33207          * <ul>
33208          *     <li ng-repeat="contact in contacts">
33209          *         <a href="#/contacts/1" ui-sref="contacts.detail({ id: contact.id })">Joe</a>
33210          *     </li>
33211          *     <li ng-repeat="contact in contacts">
33212          *         <a href="#/contacts/2" ui-sref="contacts.detail({ id: contact.id })">Alice</a>
33213          *     </li>
33214          *     <li ng-repeat="contact in contacts">
33215          *         <a href="#/contacts/3" ui-sref="contacts.detail({ id: contact.id })">Bob</a>
33216          *     </li>
33217          * </ul>
33218          *
33219          * <a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
33220          * </pre>
33221          *
33222          * @param {string} ui-sref 'stateName' can be any valid absolute or relative state
33223          * @param {Object} ui-sref-opts options to pass to {@link ui.router.state.$state#go $state.go()}
33224          */
33225         $StateRefDirective.$inject = ['$state', '$timeout'];
33226         function $StateRefDirective($state, $timeout) {
33227           var allowedOptions = ['location', 'inherit', 'reload', 'absolute'];
33228
33229           return {
33230             restrict: 'A',
33231             require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
33232             link: function(scope, element, attrs, uiSrefActive) {
33233               var ref = parseStateRef(attrs.uiSref, $state.current.name);
33234               var params = null, url = null, base = stateContext(element) || $state.$current;
33235               // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
33236               var hrefKind = Object.prototype.toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
33237                          'xlink:href' : 'href';
33238               var newHref = null, isAnchor = element.prop("tagName").toUpperCase() === "A";
33239               var isForm = element[0].nodeName === "FORM";
33240               var attr = isForm ? "action" : hrefKind, nav = true;
33241
33242               var options = { relative: base, inherit: true };
33243               var optionsOverride = scope.$eval(attrs.uiSrefOpts) || {};
33244
33245               angular.forEach(allowedOptions, function(option) {
33246                 if (option in optionsOverride) {
33247                   options[option] = optionsOverride[option];
33248                 }
33249               });
33250
33251               var update = function(newVal) {
33252                 if (newVal) params = angular.copy(newVal);
33253                 if (!nav) return;
33254
33255                 newHref = $state.href(ref.state, params, options);
33256
33257                 var activeDirective = uiSrefActive[1] || uiSrefActive[0];
33258                 if (activeDirective) {
33259                   activeDirective.$$addStateInfo(ref.state, params);
33260                 }
33261                 if (newHref === null) {
33262                   nav = false;
33263                   return false;
33264                 }
33265                 attrs.$set(attr, newHref);
33266               };
33267
33268               if (ref.paramExpr) {
33269                 scope.$watch(ref.paramExpr, function(newVal, oldVal) {
33270                   if (newVal !== params) update(newVal);
33271                 }, true);
33272                 params = angular.copy(scope.$eval(ref.paramExpr));
33273               }
33274               update();
33275
33276               if (isForm) return;
33277
33278               element.bind("click", function(e) {
33279                 var button = e.which || e.button;
33280                 if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) {
33281                   // HACK: This is to allow ng-clicks to be processed before the transition is initiated:
33282                   var transition = $timeout(function() {
33283                     $state.go(ref.state, params, options);
33284                   });
33285                   e.preventDefault();
33286
33287                   // if the state has no URL, ignore one preventDefault from the <a> directive.
33288                   var ignorePreventDefaultCount = isAnchor && !newHref ? 1: 0;
33289                   e.preventDefault = function() {
33290                     if (ignorePreventDefaultCount-- <= 0)
33291                       $timeout.cancel(transition);
33292                   };
33293                 }
33294               });
33295             }
33296           };
33297         }
33298
33299         /**
33300          * @ngdoc directive
33301          * @name ui.router.state.directive:ui-sref-active
33302          *
33303          * @requires ui.router.state.$state
33304          * @requires ui.router.state.$stateParams
33305          * @requires $interpolate
33306          *
33307          * @restrict A
33308          *
33309          * @description
33310          * A directive working alongside ui-sref to add classes to an element when the
33311          * related ui-sref directive's state is active, and removing them when it is inactive.
33312          * The primary use-case is to simplify the special appearance of navigation menus
33313          * relying on `ui-sref`, by having the "active" state's menu button appear different,
33314          * distinguishing it from the inactive menu items.
33315          *
33316          * ui-sref-active can live on the same element as ui-sref or on a parent element. The first
33317          * ui-sref-active found at the same level or above the ui-sref will be used.
33318          *
33319          * Will activate when the ui-sref's target state or any child state is active. If you
33320          * need to activate only when the ui-sref target state is active and *not* any of
33321          * it's children, then you will use
33322          * {@link ui.router.state.directive:ui-sref-active-eq ui-sref-active-eq}
33323          *
33324          * @example
33325          * Given the following template:
33326          * <pre>
33327          * <ul>
33328          *   <li ui-sref-active="active" class="item">
33329          *     <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
33330          *   </li>
33331          * </ul>
33332          * </pre>
33333          *
33334          *
33335          * When the app state is "app.user" (or any children states), and contains the state parameter "user" with value "bilbobaggins",
33336          * the resulting HTML will appear as (note the 'active' class):
33337          * <pre>
33338          * <ul>
33339          *   <li ui-sref-active="active" class="item active">
33340          *     <a ui-sref="app.user({user: 'bilbobaggins'})" href="/users/bilbobaggins">@bilbobaggins</a>
33341          *   </li>
33342          * </ul>
33343          * </pre>
33344          *
33345          * The class name is interpolated **once** during the directives link time (any further changes to the
33346          * interpolated value are ignored).
33347          *
33348          * Multiple classes may be specified in a space-separated format:
33349          * <pre>
33350          * <ul>
33351          *   <li ui-sref-active='class1 class2 class3'>
33352          *     <a ui-sref="app.user">link</a>
33353          *   </li>
33354          * </ul>
33355          * </pre>
33356          */
33357
33358         /**
33359          * @ngdoc directive
33360          * @name ui.router.state.directive:ui-sref-active-eq
33361          *
33362          * @requires ui.router.state.$state
33363          * @requires ui.router.state.$stateParams
33364          * @requires $interpolate
33365          *
33366          * @restrict A
33367          *
33368          * @description
33369          * The same as {@link ui.router.state.directive:ui-sref-active ui-sref-active} but will only activate
33370          * when the exact target state used in the `ui-sref` is active; no child states.
33371          *
33372          */
33373         $StateRefActiveDirective.$inject = ['$state', '$stateParams', '$interpolate'];
33374         function $StateRefActiveDirective($state, $stateParams, $interpolate) {
33375           return  {
33376             restrict: "A",
33377             controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
33378               var states = [], activeClass;
33379
33380               // There probably isn't much point in $observing this
33381               // uiSrefActive and uiSrefActiveEq share the same directive object with some
33382               // slight difference in logic routing
33383               activeClass = $interpolate($attrs.uiSrefActiveEq || $attrs.uiSrefActive || '', false)($scope);
33384
33385               // Allow uiSref to communicate with uiSrefActive[Equals]
33386               this.$$addStateInfo = function (newState, newParams) {
33387                 var state = $state.get(newState, stateContext($element));
33388
33389                 states.push({
33390                   state: state || { name: newState },
33391                   params: newParams
33392                 });
33393
33394                 update();
33395               };
33396
33397               $scope.$on('$stateChangeSuccess', update);
33398
33399               // Update route state
33400               function update() {
33401                 if (anyMatch()) {
33402                   $element.addClass(activeClass);
33403                 } else {
33404                   $element.removeClass(activeClass);
33405                 }
33406               }
33407
33408               function anyMatch() {
33409                 for (var i = 0; i < states.length; i++) {
33410                   if (isMatch(states[i].state, states[i].params)) {
33411                     return true;
33412                   }
33413                 }
33414                 return false;
33415               }
33416
33417               function isMatch(state, params) {
33418                 if (typeof $attrs.uiSrefActiveEq !== 'undefined') {
33419                   return $state.is(state.name, params);
33420                 } else {
33421                   return $state.includes(state.name, params);
33422                 }
33423               }
33424             }]
33425           };
33426         }
33427
33428         angular.module('ui.router.state')
33429           .directive('uiSref', $StateRefDirective)
33430           .directive('uiSrefActive', $StateRefActiveDirective)
33431           .directive('uiSrefActiveEq', $StateRefActiveDirective);
33432
33433         /**
33434          * @ngdoc filter
33435          * @name ui.router.state.filter:isState
33436          *
33437          * @requires ui.router.state.$state
33438          *
33439          * @description
33440          * Translates to {@link ui.router.state.$state#methods_is $state.is("stateName")}.
33441          */
33442         $IsStateFilter.$inject = ['$state'];
33443         function $IsStateFilter($state) {
33444           var isFilter = function (state) {
33445             return $state.is(state);
33446           };
33447           isFilter.$stateful = true;
33448           return isFilter;
33449         }
33450
33451         /**
33452          * @ngdoc filter
33453          * @name ui.router.state.filter:includedByState
33454          *
33455          * @requires ui.router.state.$state
33456          *
33457          * @description
33458          * Translates to {@link ui.router.state.$state#methods_includes $state.includes('fullOrPartialStateName')}.
33459          */
33460         $IncludedByStateFilter.$inject = ['$state'];
33461         function $IncludedByStateFilter($state) {
33462           var includesFilter = function (state) {
33463             return $state.includes(state);
33464           };
33465           includesFilter.$stateful = true;
33466           return  includesFilter;
33467         }
33468
33469         angular.module('ui.router.state')
33470           .filter('isState', $IsStateFilter)
33471           .filter('includedByState', $IncludedByStateFilter);
33472         })(window, window.angular);
33473
33474 /***/ },
33475 /* 4 */
33476 /***/ function(module, exports, __webpack_require__) {
33477
33478         __webpack_require__(5);
33479         module.exports = 'ngResource';
33480
33481
33482 /***/ },
33483 /* 5 */
33484 /***/ function(module, exports) {
33485
33486         /**
33487          * @license AngularJS v1.4.8
33488          * (c) 2010-2015 Google, Inc. http://angularjs.org
33489          * License: MIT
33490          */
33491         (function(window, angular, undefined) {'use strict';
33492
33493         var $resourceMinErr = angular.$$minErr('$resource');
33494
33495         // Helper functions and regex to lookup a dotted path on an object
33496         // stopping at undefined/null.  The path must be composed of ASCII
33497         // identifiers (just like $parse)
33498         var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;
33499
33500         function isValidDottedPath(path) {
33501           return (path != null && path !== '' && path !== 'hasOwnProperty' &&
33502               MEMBER_NAME_REGEX.test('.' + path));
33503         }
33504
33505         function lookupDottedPath(obj, path) {
33506           if (!isValidDottedPath(path)) {
33507             throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
33508           }
33509           var keys = path.split('.');
33510           for (var i = 0, ii = keys.length; i < ii && angular.isDefined(obj); i++) {
33511             var key = keys[i];
33512             obj = (obj !== null) ? obj[key] : undefined;
33513           }
33514           return obj;
33515         }
33516
33517         /**
33518          * Create a shallow copy of an object and clear other fields from the destination
33519          */
33520         function shallowClearAndCopy(src, dst) {
33521           dst = dst || {};
33522
33523           angular.forEach(dst, function(value, key) {
33524             delete dst[key];
33525           });
33526
33527           for (var key in src) {
33528             if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
33529               dst[key] = src[key];
33530             }
33531           }
33532
33533           return dst;
33534         }
33535
33536         /**
33537          * @ngdoc module
33538          * @name ngResource
33539          * @description
33540          *
33541          * # ngResource
33542          *
33543          * The `ngResource` module provides interaction support with RESTful services
33544          * via the $resource service.
33545          *
33546          *
33547          * <div doc-module-components="ngResource"></div>
33548          *
33549          * See {@link ngResource.$resource `$resource`} for usage.
33550          */
33551
33552         /**
33553          * @ngdoc service
33554          * @name $resource
33555          * @requires $http
33556          *
33557          * @description
33558          * A factory which creates a resource object that lets you interact with
33559          * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
33560          *
33561          * The returned resource object has action methods which provide high-level behaviors without
33562          * the need to interact with the low level {@link ng.$http $http} service.
33563          *
33564          * Requires the {@link ngResource `ngResource`} module to be installed.
33565          *
33566          * By default, trailing slashes will be stripped from the calculated URLs,
33567          * which can pose problems with server backends that do not expect that
33568          * behavior.  This can be disabled by configuring the `$resourceProvider` like
33569          * this:
33570          *
33571          * ```js
33572              app.config(['$resourceProvider', function($resourceProvider) {
33573                // Don't strip trailing slashes from calculated URLs
33574                $resourceProvider.defaults.stripTrailingSlashes = false;
33575              }]);
33576          * ```
33577          *
33578          * @param {string} url A parameterized URL template with parameters prefixed by `:` as in
33579          *   `/user/:username`. If you are using a URL with a port number (e.g.
33580          *   `http://example.com:8080/api`), it will be respected.
33581          *
33582          *   If you are using a url with a suffix, just add the suffix, like this:
33583          *   `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
33584          *   or even `$resource('http://example.com/resource/:resource_id.:format')`
33585          *   If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
33586          *   collapsed down to a single `.`.  If you need this sequence to appear and not collapse then you
33587          *   can escape it with `/\.`.
33588          *
33589          * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
33590          *   `actions` methods. If any of the parameter value is a function, it will be executed every time
33591          *   when a param value needs to be obtained for a request (unless the param was overridden).
33592          *
33593          *   Each key value in the parameter object is first bound to url template if present and then any
33594          *   excess keys are appended to the url search query after the `?`.
33595          *
33596          *   Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
33597          *   URL `/path/greet?salutation=Hello`.
33598          *
33599          *   If the parameter value is prefixed with `@` then the value for that parameter will be extracted
33600          *   from the corresponding property on the `data` object (provided when calling an action method).  For
33601          *   example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam`
33602          *   will be `data.someProp`.
33603          *
33604          * @param {Object.<Object>=} actions Hash with declaration of custom actions that should extend
33605          *   the default set of resource actions. The declaration should be created in the format of {@link
33606          *   ng.$http#usage $http.config}:
33607          *
33608          *       {action1: {method:?, params:?, isArray:?, headers:?, ...},
33609          *        action2: {method:?, params:?, isArray:?, headers:?, ...},
33610          *        ...}
33611          *
33612          *   Where:
33613          *
33614          *   - **`action`** – {string} – The name of action. This name becomes the name of the method on
33615          *     your resource object.
33616          *   - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
33617          *     `DELETE`, `JSONP`, etc).
33618          *   - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
33619          *     the parameter value is a function, it will be executed every time when a param value needs to
33620          *     be obtained for a request (unless the param was overridden).
33621          *   - **`url`** – {string} – action specific `url` override. The url templating is supported just
33622          *     like for the resource-level urls.
33623          *   - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
33624          *     see `returns` section.
33625          *   - **`transformRequest`** –
33626          *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
33627          *     transform function or an array of such functions. The transform function takes the http
33628          *     request body and headers and returns its transformed (typically serialized) version.
33629          *     By default, transformRequest will contain one function that checks if the request data is
33630          *     an object and serializes to using `angular.toJson`. To prevent this behavior, set
33631          *     `transformRequest` to an empty array: `transformRequest: []`
33632          *   - **`transformResponse`** –
33633          *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
33634          *     transform function or an array of such functions. The transform function takes the http
33635          *     response body and headers and returns its transformed (typically deserialized) version.
33636          *     By default, transformResponse will contain one function that checks if the response looks like
33637          *     a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
33638          *     `transformResponse` to an empty array: `transformResponse: []`
33639          *   - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
33640          *     GET request, otherwise if a cache instance built with
33641          *     {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
33642          *     caching.
33643          *   - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
33644          *     should abort the request when resolved.
33645          *   - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
33646          *     XHR object. See
33647          *     [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
33648          *     for more information.
33649          *   - **`responseType`** - `{string}` - see
33650          *     [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
33651          *   - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
33652          *     `response` and `responseError`. Both `response` and `responseError` interceptors get called
33653          *     with `http response` object. See {@link ng.$http $http interceptors}.
33654          *
33655          * @param {Object} options Hash with custom settings that should extend the
33656          *   default `$resourceProvider` behavior.  The only supported option is
33657          *
33658          *   Where:
33659          *
33660          *   - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
33661          *   slashes from any calculated URL will be stripped. (Defaults to true.)
33662          *
33663          * @returns {Object} A resource "class" object with methods for the default set of resource actions
33664          *   optionally extended with custom `actions`. The default set contains these actions:
33665          *   ```js
33666          *   { 'get':    {method:'GET'},
33667          *     'save':   {method:'POST'},
33668          *     'query':  {method:'GET', isArray:true},
33669          *     'remove': {method:'DELETE'},
33670          *     'delete': {method:'DELETE'} };
33671          *   ```
33672          *
33673          *   Calling these methods invoke an {@link ng.$http} with the specified http method,
33674          *   destination and parameters. When the data is returned from the server then the object is an
33675          *   instance of the resource class. The actions `save`, `remove` and `delete` are available on it
33676          *   as  methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
33677          *   read, update, delete) on server-side data like this:
33678          *   ```js
33679          *   var User = $resource('/user/:userId', {userId:'@id'});
33680          *   var user = User.get({userId:123}, function() {
33681          *     user.abc = true;
33682          *     user.$save();
33683          *   });
33684          *   ```
33685          *
33686          *   It is important to realize that invoking a $resource object method immediately returns an
33687          *   empty reference (object or array depending on `isArray`). Once the data is returned from the
33688          *   server the existing reference is populated with the actual data. This is a useful trick since
33689          *   usually the resource is assigned to a model which is then rendered by the view. Having an empty
33690          *   object results in no rendering, once the data arrives from the server then the object is
33691          *   populated with the data and the view automatically re-renders itself showing the new data. This
33692          *   means that in most cases one never has to write a callback function for the action methods.
33693          *
33694          *   The action methods on the class object or instance object can be invoked with the following
33695          *   parameters:
33696          *
33697          *   - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
33698          *   - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
33699          *   - non-GET instance actions:  `instance.$action([parameters], [success], [error])`
33700          *
33701          *
33702          *   Success callback is called with (value, responseHeaders) arguments, where the value is
33703          *   the populated resource instance or collection object. The error callback is called
33704          *   with (httpResponse) argument.
33705          *
33706          *   Class actions return empty instance (with additional properties below).
33707          *   Instance actions return promise of the action.
33708          *
33709          *   The Resource instances and collection have these additional properties:
33710          *
33711          *   - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
33712          *     instance or collection.
33713          *
33714          *     On success, the promise is resolved with the same resource instance or collection object,
33715          *     updated with data from server. This makes it easy to use in
33716          *     {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
33717          *     rendering until the resource(s) are loaded.
33718          *
33719          *     On failure, the promise is resolved with the {@link ng.$http http response} object, without
33720          *     the `resource` property.
33721          *
33722          *     If an interceptor object was provided, the promise will instead be resolved with the value
33723          *     returned by the interceptor.
33724          *
33725          *   - `$resolved`: `true` after first server interaction is completed (either with success or
33726          *      rejection), `false` before that. Knowing if the Resource has been resolved is useful in
33727          *      data-binding.
33728          *
33729          * @example
33730          *
33731          * # Credit card resource
33732          *
33733          * ```js
33734              // Define CreditCard class
33735              var CreditCard = $resource('/user/:userId/card/:cardId',
33736               {userId:123, cardId:'@id'}, {
33737                charge: {method:'POST', params:{charge:true}}
33738               });
33739
33740              // We can retrieve a collection from the server
33741              var cards = CreditCard.query(function() {
33742                // GET: /user/123/card
33743                // server returns: [ {id:456, number:'1234', name:'Smith'} ];
33744
33745                var card = cards[0];
33746                // each item is an instance of CreditCard
33747                expect(card instanceof CreditCard).toEqual(true);
33748                card.name = "J. Smith";
33749                // non GET methods are mapped onto the instances
33750                card.$save();
33751                // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
33752                // server returns: {id:456, number:'1234', name: 'J. Smith'};
33753
33754                // our custom method is mapped as well.
33755                card.$charge({amount:9.99});
33756                // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
33757              });
33758
33759              // we can create an instance as well
33760              var newCard = new CreditCard({number:'0123'});
33761              newCard.name = "Mike Smith";
33762              newCard.$save();
33763              // POST: /user/123/card {number:'0123', name:'Mike Smith'}
33764              // server returns: {id:789, number:'0123', name: 'Mike Smith'};
33765              expect(newCard.id).toEqual(789);
33766          * ```
33767          *
33768          * The object returned from this function execution is a resource "class" which has "static" method
33769          * for each action in the definition.
33770          *
33771          * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
33772          * `headers`.
33773          * When the data is returned from the server then the object is an instance of the resource type and
33774          * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
33775          * operations (create, read, update, delete) on server-side data.
33776
33777            ```js
33778              var User = $resource('/user/:userId', {userId:'@id'});
33779              User.get({userId:123}, function(user) {
33780                user.abc = true;
33781                user.$save();
33782              });
33783            ```
33784          *
33785          * It's worth noting that the success callback for `get`, `query` and other methods gets passed
33786          * in the response that came from the server as well as $http header getter function, so one
33787          * could rewrite the above example and get access to http headers as:
33788          *
33789            ```js
33790              var User = $resource('/user/:userId', {userId:'@id'});
33791              User.get({userId:123}, function(u, getResponseHeaders){
33792                u.abc = true;
33793                u.$save(function(u, putResponseHeaders) {
33794                  //u => saved user object
33795                  //putResponseHeaders => $http header getter
33796                });
33797              });
33798            ```
33799          *
33800          * You can also access the raw `$http` promise via the `$promise` property on the object returned
33801          *
33802            ```
33803              var User = $resource('/user/:userId', {userId:'@id'});
33804              User.get({userId:123})
33805                  .$promise.then(function(user) {
33806                    $scope.user = user;
33807                  });
33808            ```
33809
33810          * # Creating a custom 'PUT' request
33811          * In this example we create a custom method on our resource to make a PUT request
33812          * ```js
33813          *    var app = angular.module('app', ['ngResource', 'ngRoute']);
33814          *
33815          *    // Some APIs expect a PUT request in the format URL/object/ID
33816          *    // Here we are creating an 'update' method
33817          *    app.factory('Notes', ['$resource', function($resource) {
33818          *    return $resource('/notes/:id', null,
33819          *        {
33820          *            'update': { method:'PUT' }
33821          *        });
33822          *    }]);
33823          *
33824          *    // In our controller we get the ID from the URL using ngRoute and $routeParams
33825          *    // We pass in $routeParams and our Notes factory along with $scope
33826          *    app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
33827                                               function($scope, $routeParams, Notes) {
33828          *    // First get a note object from the factory
33829          *    var note = Notes.get({ id:$routeParams.id });
33830          *    $id = note.id;
33831          *
33832          *    // Now call update passing in the ID first then the object you are updating
33833          *    Notes.update({ id:$id }, note);
33834          *
33835          *    // This will PUT /notes/ID with the note object in the request payload
33836          *    }]);
33837          * ```
33838          */
33839         angular.module('ngResource', ['ng']).
33840           provider('$resource', function() {
33841             var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
33842             var provider = this;
33843
33844             this.defaults = {
33845               // Strip slashes by default
33846               stripTrailingSlashes: true,
33847
33848               // Default actions configuration
33849               actions: {
33850                 'get': {method: 'GET'},
33851                 'save': {method: 'POST'},
33852                 'query': {method: 'GET', isArray: true},
33853                 'remove': {method: 'DELETE'},
33854                 'delete': {method: 'DELETE'}
33855               }
33856             };
33857
33858             this.$get = ['$http', '$q', function($http, $q) {
33859
33860               var noop = angular.noop,
33861                 forEach = angular.forEach,
33862                 extend = angular.extend,
33863                 copy = angular.copy,
33864                 isFunction = angular.isFunction;
33865
33866               /**
33867                * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
33868                * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
33869                * (pchar) allowed in path segments:
33870                *    segment       = *pchar
33871                *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
33872                *    pct-encoded   = "%" HEXDIG HEXDIG
33873                *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
33874                *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
33875                *                     / "*" / "+" / "," / ";" / "="
33876                */
33877               function encodeUriSegment(val) {
33878                 return encodeUriQuery(val, true).
33879                   replace(/%26/gi, '&').
33880                   replace(/%3D/gi, '=').
33881                   replace(/%2B/gi, '+');
33882               }
33883
33884
33885               /**
33886                * This method is intended for encoding *key* or *value* parts of query component. We need a
33887                * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
33888                * have to be encoded per http://tools.ietf.org/html/rfc3986:
33889                *    query       = *( pchar / "/" / "?" )
33890                *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
33891                *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
33892                *    pct-encoded   = "%" HEXDIG HEXDIG
33893                *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
33894                *                     / "*" / "+" / "," / ";" / "="
33895                */
33896               function encodeUriQuery(val, pctEncodeSpaces) {
33897                 return encodeURIComponent(val).
33898                   replace(/%40/gi, '@').
33899                   replace(/%3A/gi, ':').
33900                   replace(/%24/g, '$').
33901                   replace(/%2C/gi, ',').
33902                   replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
33903               }
33904
33905               function Route(template, defaults) {
33906                 this.template = template;
33907                 this.defaults = extend({}, provider.defaults, defaults);
33908                 this.urlParams = {};
33909               }
33910
33911               Route.prototype = {
33912                 setUrlParams: function(config, params, actionUrl) {
33913                   var self = this,
33914                     url = actionUrl || self.template,
33915                     val,
33916                     encodedVal,
33917                     protocolAndDomain = '';
33918
33919                   var urlParams = self.urlParams = {};
33920                   forEach(url.split(/\W/), function(param) {
33921                     if (param === 'hasOwnProperty') {
33922                       throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
33923                     }
33924                     if (!(new RegExp("^\\d+$").test(param)) && param &&
33925                       (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
33926                       urlParams[param] = true;
33927                     }
33928                   });
33929                   url = url.replace(/\\:/g, ':');
33930                   url = url.replace(PROTOCOL_AND_DOMAIN_REGEX, function(match) {
33931                     protocolAndDomain = match;
33932                     return '';
33933                   });
33934
33935                   params = params || {};
33936                   forEach(self.urlParams, function(_, urlParam) {
33937                     val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
33938                     if (angular.isDefined(val) && val !== null) {
33939                       encodedVal = encodeUriSegment(val);
33940                       url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
33941                         return encodedVal + p1;
33942                       });
33943                     } else {
33944                       url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
33945                           leadingSlashes, tail) {
33946                         if (tail.charAt(0) == '/') {
33947                           return tail;
33948                         } else {
33949                           return leadingSlashes + tail;
33950                         }
33951                       });
33952                     }
33953                   });
33954
33955                   // strip trailing slashes and set the url (unless this behavior is specifically disabled)
33956                   if (self.defaults.stripTrailingSlashes) {
33957                     url = url.replace(/\/+$/, '') || '/';
33958                   }
33959
33960                   // then replace collapse `/.` if found in the last URL path segment before the query
33961                   // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
33962                   url = url.replace(/\/\.(?=\w+($|\?))/, '.');
33963                   // replace escaped `/\.` with `/.`
33964                   config.url = protocolAndDomain + url.replace(/\/\\\./, '/.');
33965
33966
33967                   // set params - delegate param encoding to $http
33968                   forEach(params, function(value, key) {
33969                     if (!self.urlParams[key]) {
33970                       config.params = config.params || {};
33971                       config.params[key] = value;
33972                     }
33973                   });
33974                 }
33975               };
33976
33977
33978               function resourceFactory(url, paramDefaults, actions, options) {
33979                 var route = new Route(url, options);
33980
33981                 actions = extend({}, provider.defaults.actions, actions);
33982
33983                 function extractParams(data, actionParams) {
33984                   var ids = {};
33985                   actionParams = extend({}, paramDefaults, actionParams);
33986                   forEach(actionParams, function(value, key) {
33987                     if (isFunction(value)) { value = value(); }
33988                     ids[key] = value && value.charAt && value.charAt(0) == '@' ?
33989                       lookupDottedPath(data, value.substr(1)) : value;
33990                   });
33991                   return ids;
33992                 }
33993
33994                 function defaultResponseInterceptor(response) {
33995                   return response.resource;
33996                 }
33997
33998                 function Resource(value) {
33999                   shallowClearAndCopy(value || {}, this);
34000                 }
34001
34002                 Resource.prototype.toJSON = function() {
34003                   var data = extend({}, this);
34004                   delete data.$promise;
34005                   delete data.$resolved;
34006                   return data;
34007                 };
34008
34009                 forEach(actions, function(action, name) {
34010                   var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
34011
34012                   Resource[name] = function(a1, a2, a3, a4) {
34013                     var params = {}, data, success, error;
34014
34015                     /* jshint -W086 */ /* (purposefully fall through case statements) */
34016                     switch (arguments.length) {
34017                       case 4:
34018                         error = a4;
34019                         success = a3;
34020                       //fallthrough
34021                       case 3:
34022                       case 2:
34023                         if (isFunction(a2)) {
34024                           if (isFunction(a1)) {
34025                             success = a1;
34026                             error = a2;
34027                             break;
34028                           }
34029
34030                           success = a2;
34031                           error = a3;
34032                           //fallthrough
34033                         } else {
34034                           params = a1;
34035                           data = a2;
34036                           success = a3;
34037                           break;
34038                         }
34039                       case 1:
34040                         if (isFunction(a1)) success = a1;
34041                         else if (hasBody) data = a1;
34042                         else params = a1;
34043                         break;
34044                       case 0: break;
34045                       default:
34046                         throw $resourceMinErr('badargs',
34047                           "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
34048                           arguments.length);
34049                     }
34050                     /* jshint +W086 */ /* (purposefully fall through case statements) */
34051
34052                     var isInstanceCall = this instanceof Resource;
34053                     var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
34054                     var httpConfig = {};
34055                     var responseInterceptor = action.interceptor && action.interceptor.response ||
34056                       defaultResponseInterceptor;
34057                     var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
34058                       undefined;
34059
34060                     forEach(action, function(value, key) {
34061                       switch (key) {
34062                         default:
34063                           httpConfig[key] = copy(value);
34064                           break;
34065                         case 'params':
34066                         case 'isArray':
34067                         case 'interceptor':
34068                           break;
34069                         case 'timeout':
34070                           httpConfig[key] = value;
34071                           break;
34072                       }
34073                     });
34074
34075                     if (hasBody) httpConfig.data = data;
34076                     route.setUrlParams(httpConfig,
34077                       extend({}, extractParams(data, action.params || {}), params),
34078                       action.url);
34079
34080                     var promise = $http(httpConfig).then(function(response) {
34081                       var data = response.data,
34082                         promise = value.$promise;
34083
34084                       if (data) {
34085                         // Need to convert action.isArray to boolean in case it is undefined
34086                         // jshint -W018
34087                         if (angular.isArray(data) !== (!!action.isArray)) {
34088                           throw $resourceMinErr('badcfg',
34089                               'Error in resource configuration for action `{0}`. Expected response to ' +
34090                               'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object',
34091                             angular.isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
34092                         }
34093                         // jshint +W018
34094                         if (action.isArray) {
34095                           value.length = 0;
34096                           forEach(data, function(item) {
34097                             if (typeof item === "object") {
34098                               value.push(new Resource(item));
34099                             } else {
34100                               // Valid JSON values may be string literals, and these should not be converted
34101                               // into objects. These items will not have access to the Resource prototype
34102                               // methods, but unfortunately there
34103                               value.push(item);
34104                             }
34105                           });
34106                         } else {
34107                           shallowClearAndCopy(data, value);
34108                           value.$promise = promise;
34109                         }
34110                       }
34111
34112                       value.$resolved = true;
34113
34114                       response.resource = value;
34115
34116                       return response;
34117                     }, function(response) {
34118                       value.$resolved = true;
34119
34120                       (error || noop)(response);
34121
34122                       return $q.reject(response);
34123                     });
34124
34125                     promise = promise.then(
34126                       function(response) {
34127                         var value = responseInterceptor(response);
34128                         (success || noop)(value, response.headers);
34129                         return value;
34130                       },
34131                       responseErrorInterceptor);
34132
34133                     if (!isInstanceCall) {
34134                       // we are creating instance / collection
34135                       // - set the initial promise
34136                       // - return the instance / collection
34137                       value.$promise = promise;
34138                       value.$resolved = false;
34139
34140                       return value;
34141                     }
34142
34143                     // instance call
34144                     return promise;
34145                   };
34146
34147
34148                   Resource.prototype['$' + name] = function(params, success, error) {
34149                     if (isFunction(params)) {
34150                       error = success; success = params; params = {};
34151                     }
34152                     var result = Resource[name].call(this, params, this, success, error);
34153                     return result.$promise || result;
34154                   };
34155                 });
34156
34157                 Resource.bind = function(additionalParamDefaults) {
34158                   return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
34159                 };
34160
34161                 return Resource;
34162               }
34163
34164               return resourceFactory;
34165             }];
34166           });
34167
34168
34169         })(window, window.angular);
34170
34171
34172 /***/ },
34173 /* 6 */
34174 /***/ function(module, exports, __webpack_require__) {
34175
34176         __webpack_require__(7);
34177
34178         module.exports = 'ui.bootstrap';
34179
34180
34181 /***/ },
34182 /* 7 */
34183 /***/ function(module, exports) {
34184
34185         /*
34186          * angular-ui-bootstrap
34187          * http://angular-ui.github.io/bootstrap/
34188
34189          * Version: 1.0.0 - 2016-01-08
34190          * License: MIT
34191          */
34192         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"]);
34193         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"]);
34194         angular.module('ui.bootstrap.collapse', [])
34195
34196           .directive('uibCollapse', ['$animate', '$injector', function($animate, $injector) {
34197             var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') : null;
34198             return {
34199               link: function(scope, element, attrs) {
34200                 if (!scope.$eval(attrs.uibCollapse)) {
34201                   element.addClass('in')
34202                     .addClass('collapse')
34203                     .css({height: 'auto'});
34204                 }
34205
34206                 function expand() {
34207                   element.removeClass('collapse')
34208                     .addClass('collapsing')
34209                     .attr('aria-expanded', true)
34210                     .attr('aria-hidden', false);
34211
34212                   if ($animateCss) {
34213                     $animateCss(element, {
34214                       addClass: 'in',
34215                       easing: 'ease',
34216                       to: { height: element[0].scrollHeight + 'px' }
34217                     }).start()['finally'](expandDone);
34218                   } else {
34219                     $animate.addClass(element, 'in', {
34220                       to: { height: element[0].scrollHeight + 'px' }
34221                     }).then(expandDone);
34222                   }
34223                 }
34224
34225                 function expandDone() {
34226                   element.removeClass('collapsing')
34227                     .addClass('collapse')
34228                     .css({height: 'auto'});
34229                 }
34230
34231                 function collapse() {
34232                   if (!element.hasClass('collapse') && !element.hasClass('in')) {
34233                     return collapseDone();
34234                   }
34235
34236                   element
34237                     // IMPORTANT: The height must be set before adding "collapsing" class.
34238                     // Otherwise, the browser attempts to animate from height 0 (in
34239                     // collapsing class) to the given height here.
34240                     .css({height: element[0].scrollHeight + 'px'})
34241                     // initially all panel collapse have the collapse class, this removal
34242                     // prevents the animation from jumping to collapsed state
34243                     .removeClass('collapse')
34244                     .addClass('collapsing')
34245                     .attr('aria-expanded', false)
34246                     .attr('aria-hidden', true);
34247
34248                   if ($animateCss) {
34249                     $animateCss(element, {
34250                       removeClass: 'in',
34251                       to: {height: '0'}
34252                     }).start()['finally'](collapseDone);
34253                   } else {
34254                     $animate.removeClass(element, 'in', {
34255                       to: {height: '0'}
34256                     }).then(collapseDone);
34257                   }
34258                 }
34259
34260                 function collapseDone() {
34261                   element.css({height: '0'}); // Required so that collapse works when animation is disabled
34262                   element.removeClass('collapsing')
34263                     .addClass('collapse');
34264                 }
34265
34266                 scope.$watch(attrs.uibCollapse, function(shouldCollapse) {
34267                   if (shouldCollapse) {
34268                     collapse();
34269                   } else {
34270                     expand();
34271                   }
34272                 });
34273               }
34274             };
34275           }]);
34276
34277         angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
34278
34279         .constant('uibAccordionConfig', {
34280           closeOthers: true
34281         })
34282
34283         .controller('UibAccordionController', ['$scope', '$attrs', 'uibAccordionConfig', function($scope, $attrs, accordionConfig) {
34284           // This array keeps track of the accordion groups
34285           this.groups = [];
34286
34287           // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
34288           this.closeOthers = function(openGroup) {
34289             var closeOthers = angular.isDefined($attrs.closeOthers) ?
34290               $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
34291             if (closeOthers) {
34292               angular.forEach(this.groups, function(group) {
34293                 if (group !== openGroup) {
34294                   group.isOpen = false;
34295                 }
34296               });
34297             }
34298           };
34299
34300           // This is called from the accordion-group directive to add itself to the accordion
34301           this.addGroup = function(groupScope) {
34302             var that = this;
34303             this.groups.push(groupScope);
34304
34305             groupScope.$on('$destroy', function(event) {
34306               that.removeGroup(groupScope);
34307             });
34308           };
34309
34310           // This is called from the accordion-group directive when to remove itself
34311           this.removeGroup = function(group) {
34312             var index = this.groups.indexOf(group);
34313             if (index !== -1) {
34314               this.groups.splice(index, 1);
34315             }
34316           };
34317         }])
34318
34319         // The accordion directive simply sets up the directive controller
34320         // and adds an accordion CSS class to itself element.
34321         .directive('uibAccordion', function() {
34322           return {
34323             controller: 'UibAccordionController',
34324             controllerAs: 'accordion',
34325             transclude: true,
34326             templateUrl: function(element, attrs) {
34327               return attrs.templateUrl || 'uib/template/accordion/accordion.html';
34328             }
34329           };
34330         })
34331
34332         // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
34333         .directive('uibAccordionGroup', function() {
34334           return {
34335             require: '^uibAccordion',         // We need this directive to be inside an accordion
34336             transclude: true,              // It transcludes the contents of the directive into the template
34337             replace: true,                // The element containing the directive will be replaced with the template
34338             templateUrl: function(element, attrs) {
34339               return attrs.templateUrl || 'uib/template/accordion/accordion-group.html';
34340             },
34341             scope: {
34342               heading: '@',               // Interpolate the heading attribute onto this scope
34343               isOpen: '=?',
34344               isDisabled: '=?'
34345             },
34346             controller: function() {
34347               this.setHeading = function(element) {
34348                 this.heading = element;
34349               };
34350             },
34351             link: function(scope, element, attrs, accordionCtrl) {
34352               accordionCtrl.addGroup(scope);
34353
34354               scope.openClass = attrs.openClass || 'panel-open';
34355               scope.panelClass = attrs.panelClass || 'panel-default';
34356               scope.$watch('isOpen', function(value) {
34357                 element.toggleClass(scope.openClass, !!value);
34358                 if (value) {
34359                   accordionCtrl.closeOthers(scope);
34360                 }
34361               });
34362
34363               scope.toggleOpen = function($event) {
34364                 if (!scope.isDisabled) {
34365                   if (!$event || $event.which === 32) {
34366                     scope.isOpen = !scope.isOpen;
34367                   }
34368                 }
34369               };
34370             }
34371           };
34372         })
34373
34374         // Use accordion-heading below an accordion-group to provide a heading containing HTML
34375         .directive('uibAccordionHeading', function() {
34376           return {
34377             transclude: true,   // Grab the contents to be used as the heading
34378             template: '',       // In effect remove this element!
34379             replace: true,
34380             require: '^uibAccordionGroup',
34381             link: function(scope, element, attrs, accordionGroupCtrl, transclude) {
34382               // Pass the heading to the accordion-group controller
34383               // so that it can be transcluded into the right place in the template
34384               // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
34385               accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
34386             }
34387           };
34388         })
34389
34390         // Use in the accordion-group template to indicate where you want the heading to be transcluded
34391         // You must provide the property on the accordion-group controller that will hold the transcluded element
34392         .directive('uibAccordionTransclude', function() {
34393           return {
34394             require: '^uibAccordionGroup',
34395             link: function(scope, element, attrs, controller) {
34396               scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) {
34397                 if (heading) {
34398                   element.find('span').html('');
34399                   element.find('span').append(heading);
34400                 }
34401               });
34402             }
34403           };
34404         });
34405
34406         angular.module('ui.bootstrap.alert', [])
34407
34408         .controller('UibAlertController', ['$scope', '$attrs', '$interpolate', '$timeout', function($scope, $attrs, $interpolate, $timeout) {
34409           $scope.closeable = !!$attrs.close;
34410
34411           var dismissOnTimeout = angular.isDefined($attrs.dismissOnTimeout) ?
34412             $interpolate($attrs.dismissOnTimeout)($scope.$parent) : null;
34413
34414           if (dismissOnTimeout) {
34415             $timeout(function() {
34416               $scope.close();
34417             }, parseInt(dismissOnTimeout, 10));
34418           }
34419         }])
34420
34421         .directive('uibAlert', function() {
34422           return {
34423             controller: 'UibAlertController',
34424             controllerAs: 'alert',
34425             templateUrl: function(element, attrs) {
34426               return attrs.templateUrl || 'uib/template/alert/alert.html';
34427             },
34428             transclude: true,
34429             replace: true,
34430             scope: {
34431               type: '@',
34432               close: '&'
34433             }
34434           };
34435         });
34436
34437         angular.module('ui.bootstrap.buttons', [])
34438
34439         .constant('uibButtonConfig', {
34440           activeClass: 'active',
34441           toggleEvent: 'click'
34442         })
34443
34444         .controller('UibButtonsController', ['uibButtonConfig', function(buttonConfig) {
34445           this.activeClass = buttonConfig.activeClass || 'active';
34446           this.toggleEvent = buttonConfig.toggleEvent || 'click';
34447         }])
34448
34449         .directive('uibBtnRadio', ['$parse', function($parse) {
34450           return {
34451             require: ['uibBtnRadio', 'ngModel'],
34452             controller: 'UibButtonsController',
34453             controllerAs: 'buttons',
34454             link: function(scope, element, attrs, ctrls) {
34455               var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
34456               var uncheckableExpr = $parse(attrs.uibUncheckable);
34457
34458               element.find('input').css({display: 'none'});
34459
34460               //model -> UI
34461               ngModelCtrl.$render = function() {
34462                 element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.uibBtnRadio)));
34463               };
34464
34465               //ui->model
34466               element.on(buttonsCtrl.toggleEvent, function() {
34467                 if (attrs.disabled) {
34468                   return;
34469                 }
34470
34471                 var isActive = element.hasClass(buttonsCtrl.activeClass);
34472
34473                 if (!isActive || angular.isDefined(attrs.uncheckable)) {
34474                   scope.$apply(function() {
34475                     ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.uibBtnRadio));
34476                     ngModelCtrl.$render();
34477                   });
34478                 }
34479               });
34480
34481               if (attrs.uibUncheckable) {
34482                 scope.$watch(uncheckableExpr, function(uncheckable) {
34483                   attrs.$set('uncheckable', uncheckable ? '' : null);
34484                 });
34485               }
34486             }
34487           };
34488         }])
34489
34490         .directive('uibBtnCheckbox', function() {
34491           return {
34492             require: ['uibBtnCheckbox', 'ngModel'],
34493             controller: 'UibButtonsController',
34494             controllerAs: 'button',
34495             link: function(scope, element, attrs, ctrls) {
34496               var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
34497
34498               element.find('input').css({display: 'none'});
34499
34500               function getTrueValue() {
34501                 return getCheckboxValue(attrs.btnCheckboxTrue, true);
34502               }
34503
34504               function getFalseValue() {
34505                 return getCheckboxValue(attrs.btnCheckboxFalse, false);
34506               }
34507
34508               function getCheckboxValue(attribute, defaultValue) {
34509                 return angular.isDefined(attribute) ? scope.$eval(attribute) : defaultValue;
34510               }
34511
34512               //model -> UI
34513               ngModelCtrl.$render = function() {
34514                 element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
34515               };
34516
34517               //ui->model
34518               element.on(buttonsCtrl.toggleEvent, function() {
34519                 if (attrs.disabled) {
34520                   return;
34521                 }
34522
34523                 scope.$apply(function() {
34524                   ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue());
34525                   ngModelCtrl.$render();
34526                 });
34527               });
34528             }
34529           };
34530         });
34531
34532         angular.module('ui.bootstrap.carousel', [])
34533
34534         .controller('UibCarouselController', ['$scope', '$element', '$interval', '$timeout', '$animate', function($scope, $element, $interval, $timeout, $animate) {
34535           var self = this,
34536             slides = self.slides = $scope.slides = [],
34537             SLIDE_DIRECTION = 'uib-slideDirection',
34538             currentIndex = -1,
34539             currentInterval, isPlaying, bufferedTransitions = [];
34540           self.currentSlide = null;
34541
34542           var destroyed = false;
34543
34544           self.addSlide = function(slide, element) {
34545             slide.$element = element;
34546             slides.push(slide);
34547             //if this is the first slide or the slide is set to active, select it
34548             if (slides.length === 1 || slide.active) {
34549               if ($scope.$currentTransition) {
34550                 $scope.$currentTransition = null;
34551               }
34552
34553               self.select(slides[slides.length - 1]);
34554               if (slides.length === 1) {
34555                 $scope.play();
34556               }
34557             } else {
34558               slide.active = false;
34559             }
34560           };
34561
34562           self.getCurrentIndex = function() {
34563             if (self.currentSlide && angular.isDefined(self.currentSlide.index)) {
34564               return +self.currentSlide.index;
34565             }
34566             return currentIndex;
34567           };
34568
34569           self.next = $scope.next = function() {
34570             var newIndex = (self.getCurrentIndex() + 1) % slides.length;
34571
34572             if (newIndex === 0 && $scope.noWrap()) {
34573               $scope.pause();
34574               return;
34575             }
34576
34577             return self.select(getSlideByIndex(newIndex), 'next');
34578           };
34579
34580           self.prev = $scope.prev = function() {
34581             var newIndex = self.getCurrentIndex() - 1 < 0 ? slides.length - 1 : self.getCurrentIndex() - 1;
34582
34583             if ($scope.noWrap() && newIndex === slides.length - 1) {
34584               $scope.pause();
34585               return;
34586             }
34587
34588             return self.select(getSlideByIndex(newIndex), 'prev');
34589           };
34590
34591           self.removeSlide = function(slide) {
34592             if (angular.isDefined(slide.index)) {
34593               slides.sort(function(a, b) {
34594                 return +a.index > +b.index;
34595               });
34596             }
34597
34598             var bufferedIndex = bufferedTransitions.indexOf(slide);
34599             if (bufferedIndex !== -1) {
34600               bufferedTransitions.splice(bufferedIndex, 1);
34601             }
34602             //get the index of the slide inside the carousel
34603             var index = slides.indexOf(slide);
34604             slides.splice(index, 1);
34605             $timeout(function() {
34606               if (slides.length > 0 && slide.active) {
34607                 if (index >= slides.length) {
34608                   self.select(slides[index - 1]);
34609                 } else {
34610                   self.select(slides[index]);
34611                 }
34612               } else if (currentIndex > index) {
34613                 currentIndex--;
34614               }
34615             });
34616
34617             //clean the currentSlide when no more slide
34618             if (slides.length === 0) {
34619               self.currentSlide = null;
34620               clearBufferedTransitions();
34621             }
34622           };
34623
34624           /* direction: "prev" or "next" */
34625           self.select = $scope.select = function(nextSlide, direction) {
34626             var nextIndex = $scope.indexOfSlide(nextSlide);
34627             //Decide direction if it's not given
34628             if (direction === undefined) {
34629               direction = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
34630             }
34631             //Prevent this user-triggered transition from occurring if there is already one in progress
34632             if (nextSlide && nextSlide !== self.currentSlide && !$scope.$currentTransition) {
34633               goNext(nextSlide, nextIndex, direction);
34634             } else if (nextSlide && nextSlide !== self.currentSlide && $scope.$currentTransition) {
34635               bufferedTransitions.push(nextSlide);
34636             }
34637           };
34638
34639           /* Allow outside people to call indexOf on slides array */
34640           $scope.indexOfSlide = function(slide) {
34641             return angular.isDefined(slide.index) ? +slide.index : slides.indexOf(slide);
34642           };
34643
34644           $scope.isActive = function(slide) {
34645             return self.currentSlide === slide;
34646           };
34647
34648           $scope.pause = function() {
34649             if (!$scope.noPause) {
34650               isPlaying = false;
34651               resetTimer();
34652             }
34653           };
34654
34655           $scope.play = function() {
34656             if (!isPlaying) {
34657               isPlaying = true;
34658               restartTimer();
34659             }
34660           };
34661
34662           $scope.$on('$destroy', function() {
34663             destroyed = true;
34664             resetTimer();
34665           });
34666
34667           $scope.$watch('noTransition', function(noTransition) {
34668             $animate.enabled($element, !noTransition);
34669           });
34670
34671           $scope.$watch('interval', restartTimer);
34672
34673           $scope.$watchCollection('slides', resetTransition);
34674
34675           function clearBufferedTransitions() {
34676             while (bufferedTransitions.length) {
34677               bufferedTransitions.shift();
34678             }
34679           }
34680
34681           function getSlideByIndex(index) {
34682             if (angular.isUndefined(slides[index].index)) {
34683               return slides[index];
34684             }
34685             for (var i = 0, l = slides.length; i < l; ++i) {
34686               if (slides[i].index === index) {
34687                 return slides[i];
34688               }
34689             }
34690           }
34691
34692           function goNext(slide, index, direction) {
34693             if (destroyed) { return; }
34694
34695             angular.extend(slide, {direction: direction, active: true});
34696             angular.extend(self.currentSlide || {}, {direction: direction, active: false});
34697             if ($animate.enabled($element) && !$scope.$currentTransition &&
34698               slide.$element && self.slides.length > 1) {
34699               slide.$element.data(SLIDE_DIRECTION, slide.direction);
34700               if (self.currentSlide && self.currentSlide.$element) {
34701                 self.currentSlide.$element.data(SLIDE_DIRECTION, slide.direction);
34702               }
34703
34704               $scope.$currentTransition = true;
34705               $animate.on('addClass', slide.$element, function(element, phase) {
34706                 if (phase === 'close') {
34707                   $scope.$currentTransition = null;
34708                   $animate.off('addClass', element);
34709                   if (bufferedTransitions.length) {
34710                     var nextSlide = bufferedTransitions.pop();
34711                     var nextIndex = $scope.indexOfSlide(nextSlide);
34712                     var nextDirection = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
34713                     clearBufferedTransitions();
34714
34715                     goNext(nextSlide, nextIndex, nextDirection);
34716                   }
34717                 }
34718               });
34719             }
34720
34721             self.currentSlide = slide;
34722             currentIndex = index;
34723
34724             //every time you change slides, reset the timer
34725             restartTimer();
34726           }
34727
34728           function resetTimer() {
34729             if (currentInterval) {
34730               $interval.cancel(currentInterval);
34731               currentInterval = null;
34732             }
34733           }
34734
34735           function resetTransition(slides) {
34736             if (!slides.length) {
34737               $scope.$currentTransition = null;
34738               clearBufferedTransitions();
34739             }
34740           }
34741
34742           function restartTimer() {
34743             resetTimer();
34744             var interval = +$scope.interval;
34745             if (!isNaN(interval) && interval > 0) {
34746               currentInterval = $interval(timerFn, interval);
34747             }
34748           }
34749
34750           function timerFn() {
34751             var interval = +$scope.interval;
34752             if (isPlaying && !isNaN(interval) && interval > 0 && slides.length) {
34753               $scope.next();
34754             } else {
34755               $scope.pause();
34756             }
34757           }
34758         }])
34759
34760         .directive('uibCarousel', function() {
34761           return {
34762             transclude: true,
34763             replace: true,
34764             controller: 'UibCarouselController',
34765             controllerAs: 'carousel',
34766             templateUrl: function(element, attrs) {
34767               return attrs.templateUrl || 'uib/template/carousel/carousel.html';
34768             },
34769             scope: {
34770               interval: '=',
34771               noTransition: '=',
34772               noPause: '=',
34773               noWrap: '&'
34774             }
34775           };
34776         })
34777
34778         .directive('uibSlide', function() {
34779           return {
34780             require: '^uibCarousel',
34781             transclude: true,
34782             replace: true,
34783             templateUrl: function(element, attrs) {
34784               return attrs.templateUrl || 'uib/template/carousel/slide.html';
34785             },
34786             scope: {
34787               active: '=?',
34788               actual: '=?',
34789               index: '=?'
34790             },
34791             link: function (scope, element, attrs, carouselCtrl) {
34792               carouselCtrl.addSlide(scope, element);
34793               //when the scope is destroyed then remove the slide from the current slides array
34794               scope.$on('$destroy', function() {
34795                 carouselCtrl.removeSlide(scope);
34796               });
34797
34798               scope.$watch('active', function(active) {
34799                 if (active) {
34800                   carouselCtrl.select(scope);
34801                 }
34802               });
34803             }
34804           };
34805         })
34806
34807         .animation('.item', ['$animateCss',
34808         function($animateCss) {
34809           var SLIDE_DIRECTION = 'uib-slideDirection';
34810
34811           function removeClass(element, className, callback) {
34812             element.removeClass(className);
34813             if (callback) {
34814               callback();
34815             }
34816           }
34817
34818           return {
34819             beforeAddClass: function(element, className, done) {
34820               if (className === 'active') {
34821                 var stopped = false;
34822                 var direction = element.data(SLIDE_DIRECTION);
34823                 var directionClass = direction === 'next' ? 'left' : 'right';
34824                 var removeClassFn = removeClass.bind(this, element,
34825                   directionClass + ' ' + direction, done);
34826                 element.addClass(direction);
34827
34828                 $animateCss(element, {addClass: directionClass})
34829                   .start()
34830                   .done(removeClassFn);
34831
34832                 return function() {
34833                   stopped = true;
34834                 };
34835               }
34836               done();
34837             },
34838             beforeRemoveClass: function (element, className, done) {
34839               if (className === 'active') {
34840                 var stopped = false;
34841                 var direction = element.data(SLIDE_DIRECTION);
34842                 var directionClass = direction === 'next' ? 'left' : 'right';
34843                 var removeClassFn = removeClass.bind(this, element, directionClass, done);
34844
34845                 $animateCss(element, {addClass: directionClass})
34846                   .start()
34847                   .done(removeClassFn);
34848
34849                 return function() {
34850                   stopped = true;
34851                 };
34852               }
34853               done();
34854             }
34855           };
34856         }]);
34857
34858         angular.module('ui.bootstrap.dateparser', [])
34859
34860         .service('uibDateParser', ['$log', '$locale', 'orderByFilter', function($log, $locale, orderByFilter) {
34861           // Pulled from https://github.com/mbostock/d3/blob/master/src/format/requote.js
34862           var SPECIAL_CHARACTERS_REGEXP = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
34863
34864           var localeId;
34865           var formatCodeToRegex;
34866
34867           this.init = function() {
34868             localeId = $locale.id;
34869
34870             this.parsers = {};
34871
34872             formatCodeToRegex = [
34873               {
34874                 key: 'yyyy',
34875                 regex: '\\d{4}',
34876                 apply: function(value) { this.year = +value; }
34877               },
34878               {
34879                 key: 'yy',
34880                 regex: '\\d{2}',
34881                 apply: function(value) { this.year = +value + 2000; }
34882               },
34883               {
34884                 key: 'y',
34885                 regex: '\\d{1,4}',
34886                 apply: function(value) { this.year = +value; }
34887               },
34888               {
34889                 key: 'M!',
34890                 regex: '0?[1-9]|1[0-2]',
34891                 apply: function(value) { this.month = value - 1; }
34892               },
34893               {
34894                 key: 'MMMM',
34895                 regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
34896                 apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); }
34897               },
34898               {
34899                 key: 'MMM',
34900                 regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
34901                 apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); }
34902               },
34903               {
34904                 key: 'MM',
34905                 regex: '0[1-9]|1[0-2]',
34906                 apply: function(value) { this.month = value - 1; }
34907               },
34908               {
34909                 key: 'M',
34910                 regex: '[1-9]|1[0-2]',
34911                 apply: function(value) { this.month = value - 1; }
34912               },
34913               {
34914                 key: 'd!',
34915                 regex: '[0-2]?[0-9]{1}|3[0-1]{1}',
34916                 apply: function(value) { this.date = +value; }
34917               },
34918               {
34919                 key: 'dd',
34920                 regex: '[0-2][0-9]{1}|3[0-1]{1}',
34921                 apply: function(value) { this.date = +value; }
34922               },
34923               {
34924                 key: 'd',
34925                 regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
34926                 apply: function(value) { this.date = +value; }
34927               },
34928               {
34929                 key: 'EEEE',
34930                 regex: $locale.DATETIME_FORMATS.DAY.join('|')
34931               },
34932               {
34933                 key: 'EEE',
34934                 regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
34935               },
34936               {
34937                 key: 'HH',
34938                 regex: '(?:0|1)[0-9]|2[0-3]',
34939                 apply: function(value) { this.hours = +value; }
34940               },
34941               {
34942                 key: 'hh',
34943                 regex: '0[0-9]|1[0-2]',
34944                 apply: function(value) { this.hours = +value; }
34945               },
34946               {
34947                 key: 'H',
34948                 regex: '1?[0-9]|2[0-3]',
34949                 apply: function(value) { this.hours = +value; }
34950               },
34951               {
34952                 key: 'h',
34953                 regex: '[0-9]|1[0-2]',
34954                 apply: function(value) { this.hours = +value; }
34955               },
34956               {
34957                 key: 'mm',
34958                 regex: '[0-5][0-9]',
34959                 apply: function(value) { this.minutes = +value; }
34960               },
34961               {
34962                 key: 'm',
34963                 regex: '[0-9]|[1-5][0-9]',
34964                 apply: function(value) { this.minutes = +value; }
34965               },
34966               {
34967                 key: 'sss',
34968                 regex: '[0-9][0-9][0-9]',
34969                 apply: function(value) { this.milliseconds = +value; }
34970               },
34971               {
34972                 key: 'ss',
34973                 regex: '[0-5][0-9]',
34974                 apply: function(value) { this.seconds = +value; }
34975               },
34976               {
34977                 key: 's',
34978                 regex: '[0-9]|[1-5][0-9]',
34979                 apply: function(value) { this.seconds = +value; }
34980               },
34981               {
34982                 key: 'a',
34983                 regex: $locale.DATETIME_FORMATS.AMPMS.join('|'),
34984                 apply: function(value) {
34985                   if (this.hours === 12) {
34986                     this.hours = 0;
34987                   }
34988
34989                   if (value === 'PM') {
34990                     this.hours += 12;
34991                   }
34992                 }
34993               },
34994               {
34995                 key: 'Z',
34996                 regex: '[+-]\\d{4}',
34997                 apply: function(value) {
34998                   var matches = value.match(/([+-])(\d{2})(\d{2})/),
34999                     sign = matches[1],
35000                     hours = matches[2],
35001                     minutes = matches[3];
35002                   this.hours += toInt(sign + hours);
35003                   this.minutes += toInt(sign + minutes);
35004                 }
35005               },
35006               {
35007                 key: 'ww',
35008                 regex: '[0-4][0-9]|5[0-3]'
35009               },
35010               {
35011                 key: 'w',
35012                 regex: '[0-9]|[1-4][0-9]|5[0-3]'
35013               },
35014               {
35015                 key: 'GGGG',
35016                 regex: $locale.DATETIME_FORMATS.ERANAMES.join('|').replace(/\s/g, '\\s')
35017               },
35018               {
35019                 key: 'GGG',
35020                 regex: $locale.DATETIME_FORMATS.ERAS.join('|')
35021               },
35022               {
35023                 key: 'GG',
35024                 regex: $locale.DATETIME_FORMATS.ERAS.join('|')
35025               },
35026               {
35027                 key: 'G',
35028                 regex: $locale.DATETIME_FORMATS.ERAS.join('|')
35029               }
35030             ];
35031           };
35032
35033           this.init();
35034
35035           function createParser(format) {
35036             var map = [], regex = format.split('');
35037
35038             // check for literal values
35039             var quoteIndex = format.indexOf('\'');
35040             if (quoteIndex > -1) {
35041               var inLiteral = false;
35042               format = format.split('');
35043               for (var i = quoteIndex; i < format.length; i++) {
35044                 if (inLiteral) {
35045                   if (format[i] === '\'') {
35046                     if (i + 1 < format.length && format[i+1] === '\'') { // escaped single quote
35047                       format[i+1] = '$';
35048                       regex[i+1] = '';
35049                     } else { // end of literal
35050                       regex[i] = '';
35051                       inLiteral = false;
35052                     }
35053                   }
35054                   format[i] = '$';
35055                 } else {
35056                   if (format[i] === '\'') { // start of literal
35057                     format[i] = '$';
35058                     regex[i] = '';
35059                     inLiteral = true;
35060                   }
35061                 }
35062               }
35063
35064               format = format.join('');
35065             }
35066
35067             angular.forEach(formatCodeToRegex, function(data) {
35068               var index = format.indexOf(data.key);
35069
35070               if (index > -1) {
35071                 format = format.split('');
35072
35073                 regex[index] = '(' + data.regex + ')';
35074                 format[index] = '$'; // Custom symbol to define consumed part of format
35075                 for (var i = index + 1, n = index + data.key.length; i < n; i++) {
35076                   regex[i] = '';
35077                   format[i] = '$';
35078                 }
35079                 format = format.join('');
35080
35081                 map.push({
35082                   index: index,
35083                   apply: data.apply,
35084                   matcher: data.regex
35085                 });
35086               }
35087             });
35088
35089             return {
35090               regex: new RegExp('^' + regex.join('') + '$'),
35091               map: orderByFilter(map, 'index')
35092             };
35093           }
35094
35095           this.parse = function(input, format, baseDate) {
35096             if (!angular.isString(input) || !format) {
35097               return input;
35098             }
35099
35100             format = $locale.DATETIME_FORMATS[format] || format;
35101             format = format.replace(SPECIAL_CHARACTERS_REGEXP, '\\$&');
35102
35103             if ($locale.id !== localeId) {
35104               this.init();
35105             }
35106
35107             if (!this.parsers[format]) {
35108               this.parsers[format] = createParser(format);
35109             }
35110
35111             var parser = this.parsers[format],
35112                 regex = parser.regex,
35113                 map = parser.map,
35114                 results = input.match(regex),
35115                 tzOffset = false;
35116             if (results && results.length) {
35117               var fields, dt;
35118               if (angular.isDate(baseDate) && !isNaN(baseDate.getTime())) {
35119                 fields = {
35120                   year: baseDate.getFullYear(),
35121                   month: baseDate.getMonth(),
35122                   date: baseDate.getDate(),
35123                   hours: baseDate.getHours(),
35124                   minutes: baseDate.getMinutes(),
35125                   seconds: baseDate.getSeconds(),
35126                   milliseconds: baseDate.getMilliseconds()
35127                 };
35128               } else {
35129                 if (baseDate) {
35130                   $log.warn('dateparser:', 'baseDate is not a valid date');
35131                 }
35132                 fields = { year: 1900, month: 0, date: 1, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 };
35133               }
35134
35135               for (var i = 1, n = results.length; i < n; i++) {
35136                 var mapper = map[i - 1];
35137                 if (mapper.matcher === 'Z') {
35138                   tzOffset = true;
35139                 }
35140
35141                 if (mapper.apply) {
35142                   mapper.apply.call(fields, results[i]);
35143                 }
35144               }
35145
35146               var datesetter = tzOffset ? Date.prototype.setUTCFullYear :
35147                 Date.prototype.setFullYear;
35148               var timesetter = tzOffset ? Date.prototype.setUTCHours :
35149                 Date.prototype.setHours;
35150
35151               if (isValid(fields.year, fields.month, fields.date)) {
35152                 if (angular.isDate(baseDate) && !isNaN(baseDate.getTime()) && !tzOffset) {
35153                   dt = new Date(baseDate);
35154                   datesetter.call(dt, fields.year, fields.month, fields.date);
35155                   timesetter.call(dt, fields.hours, fields.minutes,
35156                     fields.seconds, fields.milliseconds);
35157                 } else {
35158                   dt = new Date(0);
35159                   datesetter.call(dt, fields.year, fields.month, fields.date);
35160                   timesetter.call(dt, fields.hours || 0, fields.minutes || 0,
35161                     fields.seconds || 0, fields.milliseconds || 0);
35162                 }
35163               }
35164
35165               return dt;
35166             }
35167           };
35168
35169           // Check if date is valid for specific month (and year for February).
35170           // Month: 0 = Jan, 1 = Feb, etc
35171           function isValid(year, month, date) {
35172             if (date < 1) {
35173               return false;
35174             }
35175
35176             if (month === 1 && date > 28) {
35177               return date === 29 && (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0);
35178             }
35179
35180             if (month === 3 || month === 5 || month === 8 || month === 10) {
35181               return date < 31;
35182             }
35183
35184             return true;
35185           }
35186
35187           function toInt(str) {
35188             return parseInt(str, 10);
35189           }
35190
35191           this.toTimezone = toTimezone;
35192           this.fromTimezone = fromTimezone;
35193           this.timezoneToOffset = timezoneToOffset;
35194           this.addDateMinutes = addDateMinutes;
35195           this.convertTimezoneToLocal = convertTimezoneToLocal;
35196           
35197           function toTimezone(date, timezone) {
35198             return date && timezone ? convertTimezoneToLocal(date, timezone) : date;
35199           }
35200
35201           function fromTimezone(date, timezone) {
35202             return date && timezone ? convertTimezoneToLocal(date, timezone, true) : date;
35203           }
35204
35205           //https://github.com/angular/angular.js/blob/4daafd3dbe6a80d578f5a31df1bb99c77559543e/src/Angular.js#L1207
35206           function timezoneToOffset(timezone, fallback) {
35207             var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
35208             return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
35209           }
35210
35211           function addDateMinutes(date, minutes) {
35212             date = new Date(date.getTime());
35213             date.setMinutes(date.getMinutes() + minutes);
35214             return date;
35215           }
35216
35217           function convertTimezoneToLocal(date, timezone, reverse) {
35218             reverse = reverse ? -1 : 1;
35219             var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
35220             return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
35221           }
35222         }]);
35223
35224         // Avoiding use of ng-class as it creates a lot of watchers when a class is to be applied to
35225         // at most one element.
35226         angular.module('ui.bootstrap.isClass', [])
35227         .directive('uibIsClass', [
35228                  '$animate',
35229         function ($animate) {
35230           //                    11111111          22222222
35231           var ON_REGEXP = /^\s*([\s\S]+?)\s+on\s+([\s\S]+?)\s*$/;
35232           //                    11111111           22222222
35233           var IS_REGEXP = /^\s*([\s\S]+?)\s+for\s+([\s\S]+?)\s*$/;
35234
35235           var dataPerTracked = {};
35236
35237           return {
35238             restrict: 'A',
35239             compile: function (tElement, tAttrs) {
35240               var linkedScopes = [];
35241               var instances = [];
35242               var expToData = {};
35243               var lastActivated = null;
35244               var onExpMatches = tAttrs.uibIsClass.match(ON_REGEXP);
35245               var onExp = onExpMatches[2];
35246               var expsStr = onExpMatches[1];
35247               var exps = expsStr.split(',');
35248
35249               return linkFn;
35250
35251               function linkFn(scope, element, attrs) {
35252                 linkedScopes.push(scope);
35253                 instances.push({
35254                   scope: scope,
35255                   element: element
35256                 });
35257
35258                 exps.forEach(function (exp, k) {
35259                   addForExp(exp, scope);
35260                 });
35261
35262                 scope.$on('$destroy', removeScope);
35263               }
35264
35265               function addForExp(exp, scope) {
35266                 var matches = exp.match(IS_REGEXP);
35267                 var clazz = scope.$eval(matches[1]);
35268                 var compareWithExp = matches[2];
35269                 var data = expToData[exp];
35270                 if (!data) {
35271                   var watchFn = function (compareWithVal) {
35272                     var newActivated = null;
35273                     instances.some(function (instance) {
35274                       var thisVal = instance.scope.$eval(onExp);
35275                       if (thisVal === compareWithVal) {
35276                         newActivated = instance;
35277                         return true;
35278                       }
35279                     });
35280                     if (data.lastActivated !== newActivated) {
35281                       if (data.lastActivated) {
35282                         $animate.removeClass(data.lastActivated.element, clazz);
35283                       }
35284                       if (newActivated) {
35285                         $animate.addClass(newActivated.element, clazz);
35286                       }
35287                       data.lastActivated = newActivated;
35288                     }
35289                   };
35290                   expToData[exp] = data = {
35291                     lastActivated: null,
35292                     scope: scope,
35293                     watchFn: watchFn,
35294                     compareWithExp: compareWithExp,
35295                     watcher: scope.$watch(compareWithExp, watchFn)
35296                   };
35297                 }
35298                 data.watchFn(scope.$eval(compareWithExp));
35299               }
35300
35301               function removeScope(e) {
35302                 var removedScope = e.targetScope;
35303                 var index = linkedScopes.indexOf(removedScope);
35304                 linkedScopes.splice(index, 1);
35305                 instances.splice(index, 1);
35306                 if (linkedScopes.length) {
35307                   var newWatchScope = linkedScopes[0];
35308                   angular.forEach(expToData, function (data) {
35309                     if (data.scope === removedScope) {
35310                       data.watcher = newWatchScope.$watch(data.compareWithExp, data.watchFn);
35311                       data.scope = newWatchScope;
35312                     }
35313                   });
35314                 }
35315                 else {
35316                   expToData = {};
35317                 }
35318               }
35319             }
35320           };
35321         }]);
35322         angular.module('ui.bootstrap.position', [])
35323
35324         /**
35325          * A set of utility methods for working with the DOM.
35326          * It is meant to be used where we need to absolute-position elements in
35327          * relation to another element (this is the case for tooltips, popovers,
35328          * typeahead suggestions etc.).
35329          */
35330           .factory('$uibPosition', ['$document', '$window', function($document, $window) {
35331             /**
35332              * Used by scrollbarWidth() function to cache scrollbar's width.
35333              * Do not access this variable directly, use scrollbarWidth() instead.
35334              */
35335             var SCROLLBAR_WIDTH;
35336             var OVERFLOW_REGEX = {
35337               normal: /(auto|scroll)/,
35338               hidden: /(auto|scroll|hidden)/
35339             };
35340             var PLACEMENT_REGEX = {
35341               auto: /\s?auto?\s?/i,
35342               primary: /^(top|bottom|left|right)$/,
35343               secondary: /^(top|bottom|left|right|center)$/,
35344               vertical: /^(top|bottom)$/
35345             };
35346
35347             return {
35348
35349               /**
35350                * Provides a raw DOM element from a jQuery/jQLite element.
35351                *
35352                * @param {element} elem - The element to convert.
35353                *
35354                * @returns {element} A HTML element.
35355                */
35356               getRawNode: function(elem) {
35357                 return elem[0] || elem;
35358               },
35359
35360               /**
35361                * Provides a parsed number for a style property.  Strips
35362                * units and casts invalid numbers to 0.
35363                *
35364                * @param {string} value - The style value to parse.
35365                *
35366                * @returns {number} A valid number.
35367                */
35368               parseStyle: function(value) {
35369                 value = parseFloat(value);
35370                 return isFinite(value) ? value : 0;
35371               },
35372
35373               /**
35374                * Provides the closest positioned ancestor.
35375                *
35376                * @param {element} element - The element to get the offest parent for.
35377                *
35378                * @returns {element} The closest positioned ancestor.
35379                */
35380               offsetParent: function(elem) {
35381                 elem = this.getRawNode(elem);
35382
35383                 var offsetParent = elem.offsetParent || $document[0].documentElement;
35384
35385                 function isStaticPositioned(el) {
35386                   return ($window.getComputedStyle(el).position || 'static') === 'static';
35387                 }
35388
35389                 while (offsetParent && offsetParent !== $document[0].documentElement && isStaticPositioned(offsetParent)) {
35390                   offsetParent = offsetParent.offsetParent;
35391                 }
35392
35393                 return offsetParent || $document[0].documentElement;
35394               },
35395
35396               /**
35397                * Provides the scrollbar width, concept from TWBS measureScrollbar()
35398                * function in https://github.com/twbs/bootstrap/blob/master/js/modal.js
35399                *
35400                * @returns {number} The width of the browser scollbar.
35401                */
35402               scrollbarWidth: function() {
35403                 if (angular.isUndefined(SCROLLBAR_WIDTH)) {
35404                   var scrollElem = angular.element('<div style="position: absolute; top: -9999px; width: 50px; height: 50px; overflow: scroll;"></div>');
35405                   $document.find('body').append(scrollElem);
35406                   SCROLLBAR_WIDTH = scrollElem[0].offsetWidth - scrollElem[0].clientWidth;
35407                   SCROLLBAR_WIDTH = isFinite(SCROLLBAR_WIDTH) ? SCROLLBAR_WIDTH : 0;
35408                   scrollElem.remove();
35409                 }
35410
35411                 return SCROLLBAR_WIDTH;
35412               },
35413
35414               /**
35415                * Provides the closest scrollable ancestor.
35416                * A port of the jQuery UI scrollParent method:
35417                * https://github.com/jquery/jquery-ui/blob/master/ui/scroll-parent.js
35418                *
35419                * @param {element} elem - The element to find the scroll parent of.
35420                * @param {boolean=} [includeHidden=false] - Should scroll style of 'hidden' be considered,
35421                *   default is false.
35422                *
35423                * @returns {element} A HTML element.
35424                */
35425               scrollParent: function(elem, includeHidden) {
35426                 elem = this.getRawNode(elem);
35427
35428                 var overflowRegex = includeHidden ? OVERFLOW_REGEX.hidden : OVERFLOW_REGEX.normal;
35429                 var documentEl = $document[0].documentElement;
35430                 var elemStyle = $window.getComputedStyle(elem);
35431                 var excludeStatic = elemStyle.position === 'absolute';
35432                 var scrollParent = elem.parentElement || documentEl;
35433
35434                 if (scrollParent === documentEl || elemStyle.position === 'fixed') {
35435                   return documentEl;
35436                 }
35437
35438                 while (scrollParent.parentElement && scrollParent !== documentEl) {
35439                   var spStyle = $window.getComputedStyle(scrollParent);
35440                   if (excludeStatic && spStyle.position !== 'static') {
35441                     excludeStatic = false;
35442                   }
35443
35444                   if (!excludeStatic && overflowRegex.test(spStyle.overflow + spStyle.overflowY + spStyle.overflowX)) {
35445                     break;
35446                   }
35447                   scrollParent = scrollParent.parentElement;
35448                 }
35449
35450                 return scrollParent;
35451               },
35452
35453               /**
35454                * Provides read-only equivalent of jQuery's position function:
35455                * http://api.jquery.com/position/ - distance to closest positioned
35456                * ancestor.  Does not account for margins by default like jQuery position.
35457                *
35458                * @param {element} elem - The element to caclulate the position on.
35459                * @param {boolean=} [includeMargins=false] - Should margins be accounted
35460                * for, default is false.
35461                *
35462                * @returns {object} An object with the following properties:
35463                *   <ul>
35464                *     <li>**width**: the width of the element</li>
35465                *     <li>**height**: the height of the element</li>
35466                *     <li>**top**: distance to top edge of offset parent</li>
35467                *     <li>**left**: distance to left edge of offset parent</li>
35468                *   </ul>
35469                */
35470               position: function(elem, includeMagins) {
35471                 elem = this.getRawNode(elem);
35472
35473                 var elemOffset = this.offset(elem);
35474                 if (includeMagins) {
35475                   var elemStyle = $window.getComputedStyle(elem);
35476                   elemOffset.top -= this.parseStyle(elemStyle.marginTop);
35477                   elemOffset.left -= this.parseStyle(elemStyle.marginLeft);
35478                 }
35479                 var parent = this.offsetParent(elem);
35480                 var parentOffset = {top: 0, left: 0};
35481
35482                 if (parent !== $document[0].documentElement) {
35483                   parentOffset = this.offset(parent);
35484                   parentOffset.top += parent.clientTop - parent.scrollTop;
35485                   parentOffset.left += parent.clientLeft - parent.scrollLeft;
35486                 }
35487
35488                 return {
35489                   width: Math.round(angular.isNumber(elemOffset.width) ? elemOffset.width : elem.offsetWidth),
35490                   height: Math.round(angular.isNumber(elemOffset.height) ? elemOffset.height : elem.offsetHeight),
35491                   top: Math.round(elemOffset.top - parentOffset.top),
35492                   left: Math.round(elemOffset.left - parentOffset.left)
35493                 };
35494               },
35495
35496               /**
35497                * Provides read-only equivalent of jQuery's offset function:
35498                * http://api.jquery.com/offset/ - distance to viewport.  Does
35499                * not account for borders, margins, or padding on the body
35500                * element.
35501                *
35502                * @param {element} elem - The element to calculate the offset on.
35503                *
35504                * @returns {object} An object with the following properties:
35505                *   <ul>
35506                *     <li>**width**: the width of the element</li>
35507                *     <li>**height**: the height of the element</li>
35508                *     <li>**top**: distance to top edge of viewport</li>
35509                *     <li>**right**: distance to bottom edge of viewport</li>
35510                *   </ul>
35511                */
35512               offset: function(elem) {
35513                 elem = this.getRawNode(elem);
35514
35515                 var elemBCR = elem.getBoundingClientRect();
35516                 return {
35517                   width: Math.round(angular.isNumber(elemBCR.width) ? elemBCR.width : elem.offsetWidth),
35518                   height: Math.round(angular.isNumber(elemBCR.height) ? elemBCR.height : elem.offsetHeight),
35519                   top: Math.round(elemBCR.top + ($window.pageYOffset || $document[0].documentElement.scrollTop)),
35520                   left: Math.round(elemBCR.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft))
35521                 };
35522               },
35523
35524               /**
35525                * Provides offset distance to the closest scrollable ancestor
35526                * or viewport.  Accounts for border and scrollbar width.
35527                *
35528                * Right and bottom dimensions represent the distance to the
35529                * respective edge of the viewport element.  If the element
35530                * edge extends beyond the viewport, a negative value will be
35531                * reported.
35532                *
35533                * @param {element} elem - The element to get the viewport offset for.
35534                * @param {boolean=} [useDocument=false] - Should the viewport be the document element instead
35535                * of the first scrollable element, default is false.
35536                * @param {boolean=} [includePadding=true] - Should the padding on the offset parent element
35537                * be accounted for, default is true.
35538                *
35539                * @returns {object} An object with the following properties:
35540                *   <ul>
35541                *     <li>**top**: distance to the top content edge of viewport element</li>
35542                *     <li>**bottom**: distance to the bottom content edge of viewport element</li>
35543                *     <li>**left**: distance to the left content edge of viewport element</li>
35544                *     <li>**right**: distance to the right content edge of viewport element</li>
35545                *   </ul>
35546                */
35547               viewportOffset: function(elem, useDocument, includePadding) {
35548                 elem = this.getRawNode(elem);
35549                 includePadding = includePadding !== false ? true : false;
35550
35551                 var elemBCR = elem.getBoundingClientRect();
35552                 var offsetBCR = {top: 0, left: 0, bottom: 0, right: 0};
35553
35554                 var offsetParent = useDocument ? $document[0].documentElement : this.scrollParent(elem);
35555                 var offsetParentBCR = offsetParent.getBoundingClientRect();
35556
35557                 offsetBCR.top = offsetParentBCR.top + offsetParent.clientTop;
35558                 offsetBCR.left = offsetParentBCR.left + offsetParent.clientLeft;
35559                 if (offsetParent === $document[0].documentElement) {
35560                   offsetBCR.top += $window.pageYOffset;
35561                   offsetBCR.left += $window.pageXOffset;
35562                 }
35563                 offsetBCR.bottom = offsetBCR.top + offsetParent.clientHeight;
35564                 offsetBCR.right = offsetBCR.left + offsetParent.clientWidth;
35565
35566                 if (includePadding) {
35567                   var offsetParentStyle = $window.getComputedStyle(offsetParent);
35568                   offsetBCR.top += this.parseStyle(offsetParentStyle.paddingTop);
35569                   offsetBCR.bottom -= this.parseStyle(offsetParentStyle.paddingBottom);
35570                   offsetBCR.left += this.parseStyle(offsetParentStyle.paddingLeft);
35571                   offsetBCR.right -= this.parseStyle(offsetParentStyle.paddingRight);
35572                 }
35573
35574                 return {
35575                   top: Math.round(elemBCR.top - offsetBCR.top),
35576                   bottom: Math.round(offsetBCR.bottom - elemBCR.bottom),
35577                   left: Math.round(elemBCR.left - offsetBCR.left),
35578                   right: Math.round(offsetBCR.right - elemBCR.right)
35579                 };
35580               },
35581
35582               /**
35583                * Provides an array of placement values parsed from a placement string.
35584                * Along with the 'auto' indicator, supported placement strings are:
35585                *   <ul>
35586                *     <li>top: element on top, horizontally centered on host element.</li>
35587                *     <li>top-left: element on top, left edge aligned with host element left edge.</li>
35588                *     <li>top-right: element on top, lerightft edge aligned with host element right edge.</li>
35589                *     <li>bottom: element on bottom, horizontally centered on host element.</li>
35590                *     <li>bottom-left: element on bottom, left edge aligned with host element left edge.</li>
35591                *     <li>bottom-right: element on bottom, right edge aligned with host element right edge.</li>
35592                *     <li>left: element on left, vertically centered on host element.</li>
35593                *     <li>left-top: element on left, top edge aligned with host element top edge.</li>
35594                *     <li>left-bottom: element on left, bottom edge aligned with host element bottom edge.</li>
35595                *     <li>right: element on right, vertically centered on host element.</li>
35596                *     <li>right-top: element on right, top edge aligned with host element top edge.</li>
35597                *     <li>right-bottom: element on right, bottom edge aligned with host element bottom edge.</li>
35598                *   </ul>
35599                * A placement string with an 'auto' indicator is expected to be
35600                * space separated from the placement, i.e: 'auto bottom-left'  If
35601                * the primary and secondary placement values do not match 'top,
35602                * bottom, left, right' then 'top' will be the primary placement and
35603                * 'center' will be the secondary placement.  If 'auto' is passed, true
35604                * will be returned as the 3rd value of the array.
35605                *
35606                * @param {string} placement - The placement string to parse.
35607                *
35608                * @returns {array} An array with the following values
35609                * <ul>
35610                *   <li>**[0]**: The primary placement.</li>
35611                *   <li>**[1]**: The secondary placement.</li>
35612                *   <li>**[2]**: If auto is passed: true, else undefined.</li>
35613                * </ul>
35614                */
35615               parsePlacement: function(placement) {
35616                 var autoPlace = PLACEMENT_REGEX.auto.test(placement);
35617                 if (autoPlace) {
35618                   placement = placement.replace(PLACEMENT_REGEX.auto, '');
35619                 }
35620
35621                 placement = placement.split('-');
35622
35623                 placement[0] = placement[0] || 'top';
35624                 if (!PLACEMENT_REGEX.primary.test(placement[0])) {
35625                   placement[0] = 'top';
35626                 }
35627
35628                 placement[1] = placement[1] || 'center';
35629                 if (!PLACEMENT_REGEX.secondary.test(placement[1])) {
35630                   placement[1] = 'center';
35631                 }
35632
35633                 if (autoPlace) {
35634                   placement[2] = true;
35635                 } else {
35636                   placement[2] = false;
35637                 }
35638
35639                 return placement;
35640               },
35641
35642               /**
35643                * Provides coordinates for an element to be positioned relative to
35644                * another element.  Passing 'auto' as part of the placement parameter
35645                * will enable smart placement - where the element fits. i.e:
35646                * 'auto left-top' will check to see if there is enough space to the left
35647                * of the hostElem to fit the targetElem, if not place right (same for secondary
35648                * top placement).  Available space is calculated using the viewportOffset
35649                * function.
35650                *
35651                * @param {element} hostElem - The element to position against.
35652                * @param {element} targetElem - The element to position.
35653                * @param {string=} [placement=top] - The placement for the targetElem,
35654                *   default is 'top'. 'center' is assumed as secondary placement for
35655                *   'top', 'left', 'right', and 'bottom' placements.  Available placements are:
35656                *   <ul>
35657                *     <li>top</li>
35658                *     <li>top-right</li>
35659                *     <li>top-left</li>
35660                *     <li>bottom</li>
35661                *     <li>bottom-left</li>
35662                *     <li>bottom-right</li>
35663                *     <li>left</li>
35664                *     <li>left-top</li>
35665                *     <li>left-bottom</li>
35666                *     <li>right</li>
35667                *     <li>right-top</li>
35668                *     <li>right-bottom</li>
35669                *   </ul>
35670                * @param {boolean=} [appendToBody=false] - Should the top and left values returned
35671                *   be calculated from the body element, default is false.
35672                *
35673                * @returns {object} An object with the following properties:
35674                *   <ul>
35675                *     <li>**top**: Value for targetElem top.</li>
35676                *     <li>**left**: Value for targetElem left.</li>
35677                *     <li>**placement**: The resolved placement.</li>
35678                *   </ul>
35679                */
35680               positionElements: function(hostElem, targetElem, placement, appendToBody) {
35681                 hostElem = this.getRawNode(hostElem);
35682                 targetElem = this.getRawNode(targetElem);
35683
35684                 // need to read from prop to support tests.
35685                 var targetWidth = angular.isDefined(targetElem.offsetWidth) ? targetElem.offsetWidth : targetElem.prop('offsetWidth');
35686                 var targetHeight = angular.isDefined(targetElem.offsetHeight) ? targetElem.offsetHeight : targetElem.prop('offsetHeight');
35687
35688                 placement = this.parsePlacement(placement);
35689
35690                 var hostElemPos = appendToBody ? this.offset(hostElem) : this.position(hostElem);
35691                 var targetElemPos = {top: 0, left: 0, placement: ''};
35692
35693                 if (placement[2]) {
35694                   var viewportOffset = this.viewportOffset(hostElem);
35695
35696                   var targetElemStyle = $window.getComputedStyle(targetElem);
35697                   var adjustedSize = {
35698                     width: targetWidth + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginLeft) + this.parseStyle(targetElemStyle.marginRight))),
35699                     height: targetHeight + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginTop) + this.parseStyle(targetElemStyle.marginBottom)))
35700                   };
35701
35702                   placement[0] = placement[0] === 'top' && adjustedSize.height > viewportOffset.top && adjustedSize.height <= viewportOffset.bottom ? 'bottom' :
35703                                  placement[0] === 'bottom' && adjustedSize.height > viewportOffset.bottom && adjustedSize.height <= viewportOffset.top ? 'top' :
35704                                  placement[0] === 'left' && adjustedSize.width > viewportOffset.left && adjustedSize.width <= viewportOffset.right ? 'right' :
35705                                  placement[0] === 'right' && adjustedSize.width > viewportOffset.right && adjustedSize.width <= viewportOffset.left ? 'left' :
35706                                  placement[0];
35707
35708                   placement[1] = placement[1] === 'top' && adjustedSize.height - hostElemPos.height > viewportOffset.bottom && adjustedSize.height - hostElemPos.height <= viewportOffset.top ? 'bottom' :
35709                                  placement[1] === 'bottom' && adjustedSize.height - hostElemPos.height > viewportOffset.top && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom ? 'top' :
35710                                  placement[1] === 'left' && adjustedSize.width - hostElemPos.width > viewportOffset.right && adjustedSize.width - hostElemPos.width <= viewportOffset.left ? 'right' :
35711                                  placement[1] === 'right' && adjustedSize.width - hostElemPos.width > viewportOffset.left && adjustedSize.width - hostElemPos.width <= viewportOffset.right ? 'left' :
35712                                  placement[1];
35713
35714                   if (placement[1] === 'center') {
35715                     if (PLACEMENT_REGEX.vertical.test(placement[0])) {
35716                       var xOverflow = hostElemPos.width / 2 - targetWidth / 2;
35717                       if (viewportOffset.left + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.right) {
35718                         placement[1] = 'left';
35719                       } else if (viewportOffset.right + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.left) {
35720                         placement[1] = 'right';
35721                       }
35722                     } else {
35723                       var yOverflow = hostElemPos.height / 2 - adjustedSize.height / 2;
35724                       if (viewportOffset.top + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom) {
35725                         placement[1] = 'top';
35726                       } else if (viewportOffset.bottom + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.top) {
35727                         placement[1] = 'bottom';
35728                       }
35729                     }
35730                   }
35731                 }
35732
35733                 switch (placement[0]) {
35734                   case 'top':
35735                     targetElemPos.top = hostElemPos.top - targetHeight;
35736                     break;
35737                   case 'bottom':
35738                     targetElemPos.top = hostElemPos.top + hostElemPos.height;
35739                     break;
35740                   case 'left':
35741                     targetElemPos.left = hostElemPos.left - targetWidth;
35742                     break;
35743                   case 'right':
35744                     targetElemPos.left = hostElemPos.left + hostElemPos.width;
35745                     break;
35746                 }
35747
35748                 switch (placement[1]) {
35749                   case 'top':
35750                     targetElemPos.top = hostElemPos.top;
35751                     break;
35752                   case 'bottom':
35753                     targetElemPos.top = hostElemPos.top + hostElemPos.height - targetHeight;
35754                     break;
35755                   case 'left':
35756                     targetElemPos.left = hostElemPos.left;
35757                     break;
35758                   case 'right':
35759                     targetElemPos.left = hostElemPos.left + hostElemPos.width - targetWidth;
35760                     break;
35761                   case 'center':
35762                     if (PLACEMENT_REGEX.vertical.test(placement[0])) {
35763                       targetElemPos.left = hostElemPos.left + hostElemPos.width / 2 - targetWidth / 2;
35764                     } else {
35765                       targetElemPos.top = hostElemPos.top + hostElemPos.height / 2 - targetHeight / 2;
35766                     }
35767                     break;
35768                 }
35769
35770                 targetElemPos.top = Math.round(targetElemPos.top);
35771                 targetElemPos.left = Math.round(targetElemPos.left);
35772                 targetElemPos.placement = placement[1] === 'center' ? placement[0] : placement[0] + '-' + placement[1];
35773
35774                 return targetElemPos;
35775               },
35776
35777               /**
35778               * Provides a way for positioning tooltip & dropdown
35779               * arrows when using placement options beyond the standard
35780               * left, right, top, or bottom.
35781               *
35782               * @param {element} elem - The tooltip/dropdown element.
35783               * @param {string} placement - The placement for the elem.
35784               */
35785               positionArrow: function(elem, placement) {
35786                 elem = this.getRawNode(elem);
35787
35788                 var isTooltip = true;
35789
35790                 var innerElem = elem.querySelector('.tooltip-inner');
35791                 if (!innerElem) {
35792                   isTooltip = false;
35793                   innerElem = elem.querySelector('.popover-inner');
35794                 }
35795                 if (!innerElem) {
35796                   return;
35797                 }
35798
35799                 var arrowElem = isTooltip ? elem.querySelector('.tooltip-arrow') : elem.querySelector('.arrow');
35800                 if (!arrowElem) {
35801                   return;
35802                 }
35803
35804                 placement = this.parsePlacement(placement);
35805                 if (placement[1] === 'center') {
35806                   // no adjustment necessary - just reset styles
35807                   angular.element(arrowElem).css({top: '', bottom: '', right: '', left: '', margin: ''});
35808                   return;
35809                 }
35810
35811                 var borderProp = 'border-' + placement[0] + '-width';
35812                 var borderWidth = $window.getComputedStyle(arrowElem)[borderProp];
35813
35814                 var borderRadiusProp = 'border-';
35815                 if (PLACEMENT_REGEX.vertical.test(placement[0])) {
35816                   borderRadiusProp += placement[0] + '-' + placement[1];
35817                 } else {
35818                   borderRadiusProp += placement[1] + '-' + placement[0];
35819                 }
35820                 borderRadiusProp += '-radius';
35821                 var borderRadius = $window.getComputedStyle(isTooltip ? innerElem : elem)[borderRadiusProp];
35822
35823                 var arrowCss = {
35824                   top: 'auto',
35825                   bottom: 'auto',
35826                   left: 'auto',
35827                   right: 'auto',
35828                   margin: 0
35829                 };
35830
35831                 switch (placement[0]) {
35832                   case 'top':
35833                     arrowCss.bottom = isTooltip ? '0' : '-' + borderWidth;
35834                     break;
35835                   case 'bottom':
35836                     arrowCss.top = isTooltip ? '0' : '-' + borderWidth;
35837                     break;
35838                   case 'left':
35839                     arrowCss.right = isTooltip ? '0' : '-' + borderWidth;
35840                     break;
35841                   case 'right':
35842                     arrowCss.left = isTooltip ? '0' : '-' + borderWidth;
35843                     break;
35844                 }
35845
35846                 arrowCss[placement[1]] = borderRadius;
35847
35848                 angular.element(arrowElem).css(arrowCss);
35849               }
35850             };
35851           }]);
35852
35853         angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.isClass', 'ui.bootstrap.position'])
35854
35855         .value('$datepickerSuppressError', false)
35856
35857         .constant('uibDatepickerConfig', {
35858           formatDay: 'dd',
35859           formatMonth: 'MMMM',
35860           formatYear: 'yyyy',
35861           formatDayHeader: 'EEE',
35862           formatDayTitle: 'MMMM yyyy',
35863           formatMonthTitle: 'yyyy',
35864           datepickerMode: 'day',
35865           minMode: 'day',
35866           maxMode: 'year',
35867           showWeeks: true,
35868           startingDay: 0,
35869           yearRows: 4,
35870           yearColumns: 5,
35871           minDate: null,
35872           maxDate: null,
35873           shortcutPropagation: false,
35874           ngModelOptions: {}
35875         })
35876
35877         .controller('UibDatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$log', 'dateFilter', 'uibDatepickerConfig', '$datepickerSuppressError', 'uibDateParser',
35878           function($scope, $attrs, $parse, $interpolate, $log, dateFilter, datepickerConfig, $datepickerSuppressError, dateParser) {
35879           var self = this,
35880               ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl;
35881               ngModelOptions = {};
35882
35883           // Modes chain
35884           this.modes = ['day', 'month', 'year'];
35885
35886           // Interpolated configuration attributes
35887           angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle'], function(key) {
35888             self[key] = angular.isDefined($attrs[key]) ? $interpolate($attrs[key])($scope.$parent) : datepickerConfig[key];
35889           });
35890
35891           // Evaled configuration attributes
35892           angular.forEach(['showWeeks', 'startingDay', 'yearRows', 'yearColumns', 'shortcutPropagation'], function(key) {
35893             self[key] = angular.isDefined($attrs[key]) ? $scope.$parent.$eval($attrs[key]) : datepickerConfig[key];
35894           });
35895
35896           // Watchable date attributes
35897           angular.forEach(['minDate', 'maxDate'], function(key) {
35898             if ($attrs[key]) {
35899               $scope.$parent.$watch($attrs[key], function(value) {
35900                 self[key] = value ? angular.isDate(value) ? dateParser.fromTimezone(new Date(value), ngModelOptions.timezone) : new Date(dateFilter(value, 'medium')) : null;
35901                 self.refreshView();
35902               });
35903             } else {
35904               self[key] = datepickerConfig[key] ? dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.timezone) : null;
35905             }
35906           });
35907
35908           angular.forEach(['minMode', 'maxMode'], function(key) {
35909             if ($attrs[key]) {
35910               $scope.$parent.$watch($attrs[key], function(value) {
35911                 self[key] = $scope[key] = angular.isDefined(value) ? value : $attrs[key];
35912                 if (key === 'minMode' && self.modes.indexOf($scope.datepickerMode) < self.modes.indexOf(self[key]) ||
35913                   key === 'maxMode' && self.modes.indexOf($scope.datepickerMode) > self.modes.indexOf(self[key])) {
35914                   $scope.datepickerMode = self[key];
35915                 }
35916               });
35917             } else {
35918               self[key] = $scope[key] = datepickerConfig[key] || null;
35919             }
35920           });
35921
35922           $scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode;
35923           $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
35924
35925           if (angular.isDefined($attrs.initDate)) {
35926             this.activeDate = dateParser.fromTimezone($scope.$parent.$eval($attrs.initDate), ngModelOptions.timezone) || new Date();
35927             $scope.$parent.$watch($attrs.initDate, function(initDate) {
35928               if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) {
35929                 self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.timezone);
35930                 self.refreshView();
35931               }
35932             });
35933           } else {
35934             this.activeDate = new Date();
35935           }
35936
35937           $scope.disabled = angular.isDefined($attrs.disabled) || false;
35938           if (angular.isDefined($attrs.ngDisabled)) {
35939             $scope.$parent.$watch($attrs.ngDisabled, function(disabled) {
35940               $scope.disabled = disabled;
35941               self.refreshView();
35942             });
35943           }
35944
35945           $scope.isActive = function(dateObject) {
35946             if (self.compare(dateObject.date, self.activeDate) === 0) {
35947               $scope.activeDateId = dateObject.uid;
35948               return true;
35949             }
35950             return false;
35951           };
35952
35953           this.init = function(ngModelCtrl_) {
35954             ngModelCtrl = ngModelCtrl_;
35955             ngModelOptions = ngModelCtrl_.$options || datepickerConfig.ngModelOptions;
35956
35957             if (ngModelCtrl.$modelValue) {
35958               this.activeDate = ngModelCtrl.$modelValue;
35959             }
35960
35961             ngModelCtrl.$render = function() {
35962               self.render();
35963             };
35964           };
35965
35966           this.render = function() {
35967             if (ngModelCtrl.$viewValue) {
35968               var date = new Date(ngModelCtrl.$viewValue),
35969                   isValid = !isNaN(date);
35970
35971               if (isValid) {
35972                 this.activeDate = dateParser.fromTimezone(date, ngModelOptions.timezone);
35973               } else if (!$datepickerSuppressError) {
35974                 $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.');
35975               }
35976             }
35977             this.refreshView();
35978           };
35979
35980           this.refreshView = function() {
35981             if (this.element) {
35982               $scope.selectedDt = null;
35983               this._refreshView();
35984               if ($scope.activeDt) {
35985                 $scope.activeDateId = $scope.activeDt.uid;
35986               }
35987
35988               var date = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
35989               date = dateParser.fromTimezone(date, ngModelOptions.timezone);
35990               ngModelCtrl.$setValidity('dateDisabled', !date ||
35991                 this.element && !this.isDisabled(date));
35992             }
35993           };
35994
35995           this.createDateObject = function(date, format) {
35996             var model = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
35997             model = dateParser.fromTimezone(model, ngModelOptions.timezone);
35998             var dt = {
35999               date: date,
36000               label: dateFilter(date, format),
36001               selected: model && this.compare(date, model) === 0,
36002               disabled: this.isDisabled(date),
36003               current: this.compare(date, new Date()) === 0,
36004               customClass: this.customClass(date) || null
36005             };
36006
36007             if (model && this.compare(date, model) === 0) {
36008               $scope.selectedDt = dt;
36009             }
36010
36011             if (self.activeDate && this.compare(dt.date, self.activeDate) === 0) {
36012               $scope.activeDt = dt;
36013             }
36014
36015             return dt;
36016           };
36017
36018           this.isDisabled = function(date) {
36019             return $scope.disabled ||
36020               this.minDate && this.compare(date, this.minDate) < 0 ||
36021               this.maxDate && this.compare(date, this.maxDate) > 0 ||
36022               $attrs.dateDisabled && $scope.dateDisabled({date: date, mode: $scope.datepickerMode});
36023           };
36024
36025           this.customClass = function(date) {
36026             return $scope.customClass({date: date, mode: $scope.datepickerMode});
36027           };
36028
36029           // Split array into smaller arrays
36030           this.split = function(arr, size) {
36031             var arrays = [];
36032             while (arr.length > 0) {
36033               arrays.push(arr.splice(0, size));
36034             }
36035             return arrays;
36036           };
36037
36038           $scope.select = function(date) {
36039             if ($scope.datepickerMode === self.minMode) {
36040               var dt = ngModelCtrl.$viewValue ? dateParser.fromTimezone(new Date(ngModelCtrl.$viewValue), ngModelOptions.timezone) : new Date(0, 0, 0, 0, 0, 0, 0);
36041               dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
36042               dt = dateParser.toTimezone(dt, ngModelOptions.timezone);
36043               ngModelCtrl.$setViewValue(dt);
36044               ngModelCtrl.$render();
36045             } else {
36046               self.activeDate = date;
36047               $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1];
36048             }
36049           };
36050
36051           $scope.move = function(direction) {
36052             var year = self.activeDate.getFullYear() + direction * (self.step.years || 0),
36053                 month = self.activeDate.getMonth() + direction * (self.step.months || 0);
36054             self.activeDate.setFullYear(year, month, 1);
36055             self.refreshView();
36056           };
36057
36058           $scope.toggleMode = function(direction) {
36059             direction = direction || 1;
36060
36061             if ($scope.datepickerMode === self.maxMode && direction === 1 ||
36062               $scope.datepickerMode === self.minMode && direction === -1) {
36063               return;
36064             }
36065
36066             $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction];
36067           };
36068
36069           // Key event mapper
36070           $scope.keys = { 13: 'enter', 32: 'space', 33: 'pageup', 34: 'pagedown', 35: 'end', 36: 'home', 37: 'left', 38: 'up', 39: 'right', 40: 'down' };
36071
36072           var focusElement = function() {
36073             self.element[0].focus();
36074           };
36075
36076           // Listen for focus requests from popup directive
36077           $scope.$on('uib:datepicker.focus', focusElement);
36078
36079           $scope.keydown = function(evt) {
36080             var key = $scope.keys[evt.which];
36081
36082             if (!key || evt.shiftKey || evt.altKey || $scope.disabled) {
36083               return;
36084             }
36085
36086             evt.preventDefault();
36087             if (!self.shortcutPropagation) {
36088               evt.stopPropagation();
36089             }
36090
36091             if (key === 'enter' || key === 'space') {
36092               if (self.isDisabled(self.activeDate)) {
36093                 return; // do nothing
36094               }
36095               $scope.select(self.activeDate);
36096             } else if (evt.ctrlKey && (key === 'up' || key === 'down')) {
36097               $scope.toggleMode(key === 'up' ? 1 : -1);
36098             } else {
36099               self.handleKeyDown(key, evt);
36100               self.refreshView();
36101             }
36102           };
36103         }])
36104
36105         .controller('UibDaypickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36106           var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
36107
36108           this.step = { months: 1 };
36109           this.element = $element;
36110           function getDaysInMonth(year, month) {
36111             return month === 1 && year % 4 === 0 &&
36112               (year % 100 !== 0 || year % 400 === 0) ? 29 : DAYS_IN_MONTH[month];
36113           }
36114
36115           this.init = function(ctrl) {
36116             angular.extend(ctrl, this);
36117             scope.showWeeks = ctrl.showWeeks;
36118             ctrl.refreshView();
36119           };
36120
36121           this.getDates = function(startDate, n) {
36122             var dates = new Array(n), current = new Date(startDate), i = 0, date;
36123             while (i < n) {
36124               date = new Date(current);
36125               dates[i++] = date;
36126               current.setDate(current.getDate() + 1);
36127             }
36128             return dates;
36129           };
36130
36131           this._refreshView = function() {
36132             var year = this.activeDate.getFullYear(),
36133               month = this.activeDate.getMonth(),
36134               firstDayOfMonth = new Date(this.activeDate);
36135
36136             firstDayOfMonth.setFullYear(year, month, 1);
36137
36138             var difference = this.startingDay - firstDayOfMonth.getDay(),
36139               numDisplayedFromPreviousMonth = difference > 0 ?
36140                 7 - difference : - difference,
36141               firstDate = new Date(firstDayOfMonth);
36142
36143             if (numDisplayedFromPreviousMonth > 0) {
36144               firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
36145             }
36146
36147             // 42 is the number of days on a six-week calendar
36148             var days = this.getDates(firstDate, 42);
36149             for (var i = 0; i < 42; i ++) {
36150               days[i] = angular.extend(this.createDateObject(days[i], this.formatDay), {
36151                 secondary: days[i].getMonth() !== month,
36152                 uid: scope.uniqueId + '-' + i
36153               });
36154             }
36155
36156             scope.labels = new Array(7);
36157             for (var j = 0; j < 7; j++) {
36158               scope.labels[j] = {
36159                 abbr: dateFilter(days[j].date, this.formatDayHeader),
36160                 full: dateFilter(days[j].date, 'EEEE')
36161               };
36162             }
36163
36164             scope.title = dateFilter(this.activeDate, this.formatDayTitle);
36165             scope.rows = this.split(days, 7);
36166
36167             if (scope.showWeeks) {
36168               scope.weekNumbers = [];
36169               var thursdayIndex = (4 + 7 - this.startingDay) % 7,
36170                   numWeeks = scope.rows.length;
36171               for (var curWeek = 0; curWeek < numWeeks; curWeek++) {
36172                 scope.weekNumbers.push(
36173                   getISO8601WeekNumber(scope.rows[curWeek][thursdayIndex].date));
36174               }
36175             }
36176           };
36177
36178           this.compare = function(date1, date2) {
36179             var _date1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
36180             var _date2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
36181             _date1.setFullYear(date1.getFullYear());
36182             _date2.setFullYear(date2.getFullYear());
36183             return _date1 - _date2;
36184           };
36185
36186           function getISO8601WeekNumber(date) {
36187             var checkDate = new Date(date);
36188             checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
36189             var time = checkDate.getTime();
36190             checkDate.setMonth(0); // Compare with Jan 1
36191             checkDate.setDate(1);
36192             return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
36193           }
36194
36195           this.handleKeyDown = function(key, evt) {
36196             var date = this.activeDate.getDate();
36197
36198             if (key === 'left') {
36199               date = date - 1;
36200             } else if (key === 'up') {
36201               date = date - 7;
36202             } else if (key === 'right') {
36203               date = date + 1;
36204             } else if (key === 'down') {
36205               date = date + 7;
36206             } else if (key === 'pageup' || key === 'pagedown') {
36207               var month = this.activeDate.getMonth() + (key === 'pageup' ? - 1 : 1);
36208               this.activeDate.setMonth(month, 1);
36209               date = Math.min(getDaysInMonth(this.activeDate.getFullYear(), this.activeDate.getMonth()), date);
36210             } else if (key === 'home') {
36211               date = 1;
36212             } else if (key === 'end') {
36213               date = getDaysInMonth(this.activeDate.getFullYear(), this.activeDate.getMonth());
36214             }
36215             this.activeDate.setDate(date);
36216           };
36217         }])
36218
36219         .controller('UibMonthpickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36220           this.step = { years: 1 };
36221           this.element = $element;
36222
36223           this.init = function(ctrl) {
36224             angular.extend(ctrl, this);
36225             ctrl.refreshView();
36226           };
36227
36228           this._refreshView = function() {
36229             var months = new Array(12),
36230                 year = this.activeDate.getFullYear(),
36231                 date;
36232
36233             for (var i = 0; i < 12; i++) {
36234               date = new Date(this.activeDate);
36235               date.setFullYear(year, i, 1);
36236               months[i] = angular.extend(this.createDateObject(date, this.formatMonth), {
36237                 uid: scope.uniqueId + '-' + i
36238               });
36239             }
36240
36241             scope.title = dateFilter(this.activeDate, this.formatMonthTitle);
36242             scope.rows = this.split(months, 3);
36243           };
36244
36245           this.compare = function(date1, date2) {
36246             var _date1 = new Date(date1.getFullYear(), date1.getMonth());
36247             var _date2 = new Date(date2.getFullYear(), date2.getMonth());
36248             _date1.setFullYear(date1.getFullYear());
36249             _date2.setFullYear(date2.getFullYear());
36250             return _date1 - _date2;
36251           };
36252
36253           this.handleKeyDown = function(key, evt) {
36254             var date = this.activeDate.getMonth();
36255
36256             if (key === 'left') {
36257               date = date - 1;
36258             } else if (key === 'up') {
36259               date = date - 3;
36260             } else if (key === 'right') {
36261               date = date + 1;
36262             } else if (key === 'down') {
36263               date = date + 3;
36264             } else if (key === 'pageup' || key === 'pagedown') {
36265               var year = this.activeDate.getFullYear() + (key === 'pageup' ? - 1 : 1);
36266               this.activeDate.setFullYear(year);
36267             } else if (key === 'home') {
36268               date = 0;
36269             } else if (key === 'end') {
36270               date = 11;
36271             }
36272             this.activeDate.setMonth(date);
36273           };
36274         }])
36275
36276         .controller('UibYearpickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36277           var columns, range;
36278           this.element = $element;
36279
36280           function getStartingYear(year) {
36281             return parseInt((year - 1) / range, 10) * range + 1;
36282           }
36283
36284           this.yearpickerInit = function() {
36285             columns = this.yearColumns;
36286             range = this.yearRows * columns;
36287             this.step = { years: range };
36288           };
36289
36290           this._refreshView = function() {
36291             var years = new Array(range), date;
36292
36293             for (var i = 0, start = getStartingYear(this.activeDate.getFullYear()); i < range; i++) {
36294               date = new Date(this.activeDate);
36295               date.setFullYear(start + i, 0, 1);
36296               years[i] = angular.extend(this.createDateObject(date, this.formatYear), {
36297                 uid: scope.uniqueId + '-' + i
36298               });
36299             }
36300
36301             scope.title = [years[0].label, years[range - 1].label].join(' - ');
36302             scope.rows = this.split(years, columns);
36303             scope.columns = columns;
36304           };
36305
36306           this.compare = function(date1, date2) {
36307             return date1.getFullYear() - date2.getFullYear();
36308           };
36309
36310           this.handleKeyDown = function(key, evt) {
36311             var date = this.activeDate.getFullYear();
36312
36313             if (key === 'left') {
36314               date = date - 1;
36315             } else if (key === 'up') {
36316               date = date - columns;
36317             } else if (key === 'right') {
36318               date = date + 1;
36319             } else if (key === 'down') {
36320               date = date + columns;
36321             } else if (key === 'pageup' || key === 'pagedown') {
36322               date += (key === 'pageup' ? - 1 : 1) * range;
36323             } else if (key === 'home') {
36324               date = getStartingYear(this.activeDate.getFullYear());
36325             } else if (key === 'end') {
36326               date = getStartingYear(this.activeDate.getFullYear()) + range - 1;
36327             }
36328             this.activeDate.setFullYear(date);
36329           };
36330         }])
36331
36332         .directive('uibDatepicker', function() {
36333           return {
36334             replace: true,
36335             templateUrl: function(element, attrs) {
36336               return attrs.templateUrl || 'uib/template/datepicker/datepicker.html';
36337             },
36338             scope: {
36339               datepickerMode: '=?',
36340               dateDisabled: '&',
36341               customClass: '&',
36342               shortcutPropagation: '&?'
36343             },
36344             require: ['uibDatepicker', '^ngModel'],
36345             controller: 'UibDatepickerController',
36346             controllerAs: 'datepicker',
36347             link: function(scope, element, attrs, ctrls) {
36348               var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
36349
36350               datepickerCtrl.init(ngModelCtrl);
36351             }
36352           };
36353         })
36354
36355         .directive('uibDaypicker', function() {
36356           return {
36357             replace: true,
36358             templateUrl: function(element, attrs) {
36359               return attrs.templateUrl || 'uib/template/datepicker/day.html';
36360             },
36361             require: ['^uibDatepicker', 'uibDaypicker'],
36362             controller: 'UibDaypickerController',
36363             link: function(scope, element, attrs, ctrls) {
36364               var datepickerCtrl = ctrls[0],
36365                 daypickerCtrl = ctrls[1];
36366
36367               daypickerCtrl.init(datepickerCtrl);
36368             }
36369           };
36370         })
36371
36372         .directive('uibMonthpicker', function() {
36373           return {
36374             replace: true,
36375             templateUrl: function(element, attrs) {
36376               return attrs.templateUrl || 'uib/template/datepicker/month.html';
36377             },
36378             require: ['^uibDatepicker', 'uibMonthpicker'],
36379             controller: 'UibMonthpickerController',
36380             link: function(scope, element, attrs, ctrls) {
36381               var datepickerCtrl = ctrls[0],
36382                 monthpickerCtrl = ctrls[1];
36383
36384               monthpickerCtrl.init(datepickerCtrl);
36385             }
36386           };
36387         })
36388
36389         .directive('uibYearpicker', function() {
36390           return {
36391             replace: true,
36392             templateUrl: function(element, attrs) {
36393               return attrs.templateUrl || 'uib/template/datepicker/year.html';
36394             },
36395             require: ['^uibDatepicker', 'uibYearpicker'],
36396             controller: 'UibYearpickerController',
36397             link: function(scope, element, attrs, ctrls) {
36398               var ctrl = ctrls[0];
36399               angular.extend(ctrl, ctrls[1]);
36400               ctrl.yearpickerInit();
36401
36402               ctrl.refreshView();
36403             }
36404           };
36405         })
36406
36407         .constant('uibDatepickerPopupConfig', {
36408           datepickerPopup: 'yyyy-MM-dd',
36409           datepickerPopupTemplateUrl: 'uib/template/datepicker/popup.html',
36410           datepickerTemplateUrl: 'uib/template/datepicker/datepicker.html',
36411           html5Types: {
36412             date: 'yyyy-MM-dd',
36413             'datetime-local': 'yyyy-MM-ddTHH:mm:ss.sss',
36414             'month': 'yyyy-MM'
36415           },
36416           currentText: 'Today',
36417           clearText: 'Clear',
36418           closeText: 'Done',
36419           closeOnDateSelection: true,
36420           appendToBody: false,
36421           showButtonBar: true,
36422           onOpenFocus: true,
36423           altInputFormats: []
36424         })
36425
36426         .controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig',
36427         function(scope, element, attrs, $compile, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig) {
36428           var self = this;
36429           var cache = {},
36430             isHtml5DateInput = false;
36431           var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
36432             datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl,
36433             ngModel, ngModelOptions, $popup, altInputFormats;
36434
36435           scope.watchData = {};
36436
36437           this.init = function(_ngModel_) {
36438             ngModel = _ngModel_;
36439             ngModelOptions = _ngModel_.$options || datepickerConfig.ngModelOptions;
36440             closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection;
36441             appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody;
36442             onOpenFocus = angular.isDefined(attrs.onOpenFocus) ? scope.$parent.$eval(attrs.onOpenFocus) : datepickerPopupConfig.onOpenFocus;
36443             datepickerPopupTemplateUrl = angular.isDefined(attrs.datepickerPopupTemplateUrl) ? attrs.datepickerPopupTemplateUrl : datepickerPopupConfig.datepickerPopupTemplateUrl;
36444             datepickerTemplateUrl = angular.isDefined(attrs.datepickerTemplateUrl) ? attrs.datepickerTemplateUrl : datepickerPopupConfig.datepickerTemplateUrl;
36445             altInputFormats = angular.isDefined(attrs.altInputFormats) ? scope.$parent.$eval(attrs.altInputFormats) : datepickerPopupConfig.altInputFormats;
36446
36447             scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar;
36448
36449             if (datepickerPopupConfig.html5Types[attrs.type]) {
36450               dateFormat = datepickerPopupConfig.html5Types[attrs.type];
36451               isHtml5DateInput = true;
36452             } else {
36453               dateFormat = attrs.uibDatepickerPopup || datepickerPopupConfig.datepickerPopup;
36454               attrs.$observe('uibDatepickerPopup', function(value, oldValue) {
36455                   var newDateFormat = value || datepickerPopupConfig.datepickerPopup;
36456                   // Invalidate the $modelValue to ensure that formatters re-run
36457                   // FIXME: Refactor when PR is merged: https://github.com/angular/angular.js/pull/10764
36458                   if (newDateFormat !== dateFormat) {
36459                     dateFormat = newDateFormat;
36460                     ngModel.$modelValue = null;
36461
36462                     if (!dateFormat) {
36463                       throw new Error('uibDatepickerPopup must have a date format specified.');
36464                     }
36465                   }
36466               });
36467             }
36468
36469             if (!dateFormat) {
36470               throw new Error('uibDatepickerPopup must have a date format specified.');
36471             }
36472
36473             if (isHtml5DateInput && attrs.uibDatepickerPopup) {
36474               throw new Error('HTML5 date input types do not support custom formats.');
36475             }
36476
36477             // popup element used to display calendar
36478             popupEl = angular.element('<div uib-datepicker-popup-wrap><div uib-datepicker></div></div>');
36479             scope.ngModelOptions = angular.copy(ngModelOptions);
36480             scope.ngModelOptions.timezone = null;
36481             popupEl.attr({
36482               'ng-model': 'date',
36483               'ng-model-options': 'ngModelOptions',
36484               'ng-change': 'dateSelection(date)',
36485               'template-url': datepickerPopupTemplateUrl
36486             });
36487
36488             // datepicker element
36489             datepickerEl = angular.element(popupEl.children()[0]);
36490             datepickerEl.attr('template-url', datepickerTemplateUrl);
36491
36492             if (isHtml5DateInput) {
36493               if (attrs.type === 'month') {
36494                 datepickerEl.attr('datepicker-mode', '"month"');
36495                 datepickerEl.attr('min-mode', 'month');
36496               }
36497             }
36498
36499             if (attrs.datepickerOptions) {
36500               var options = scope.$parent.$eval(attrs.datepickerOptions);
36501               if (options && options.initDate) {
36502                 scope.initDate = dateParser.fromTimezone(options.initDate, ngModelOptions.timezone);
36503                 datepickerEl.attr('init-date', 'initDate');
36504                 delete options.initDate;
36505               }
36506               angular.forEach(options, function(value, option) {
36507                 datepickerEl.attr(cameltoDash(option), value);
36508               });
36509             }
36510
36511             angular.forEach(['minMode', 'maxMode'], function(key) {
36512               if (attrs[key]) {
36513                 scope.$parent.$watch(function() { return attrs[key]; }, function(value) {
36514                   scope.watchData[key] = value;
36515                 });
36516                 datepickerEl.attr(cameltoDash(key), 'watchData.' + key);
36517               }
36518             });
36519
36520             angular.forEach(['datepickerMode', 'shortcutPropagation'], function(key) {
36521               if (attrs[key]) {
36522                 var getAttribute = $parse(attrs[key]);
36523                 var propConfig = {
36524                   get: function() {
36525                     return getAttribute(scope.$parent);
36526                   }
36527                 };
36528
36529                 datepickerEl.attr(cameltoDash(key), 'watchData.' + key);
36530
36531                 // Propagate changes from datepicker to outside
36532                 if (key === 'datepickerMode') {
36533                   var setAttribute = getAttribute.assign;
36534                   propConfig.set = function(v) {
36535                     setAttribute(scope.$parent, v);
36536                   };
36537                 }
36538
36539                 Object.defineProperty(scope.watchData, key, propConfig);
36540               }
36541             });
36542
36543             angular.forEach(['minDate', 'maxDate', 'initDate'], function(key) {
36544               if (attrs[key]) {
36545                 var getAttribute = $parse(attrs[key]);
36546
36547                 scope.$parent.$watch(getAttribute, function(value) {
36548                   if (key === 'minDate' || key === 'maxDate') {
36549                     cache[key] = angular.isDate(value) ? dateParser.fromTimezone(new Date(value), ngModelOptions.timezone) : new Date(dateFilter(value, 'medium'));
36550                   }
36551
36552                   scope.watchData[key] = cache[key] || dateParser.fromTimezone(new Date(value), ngModelOptions.timezone);
36553                 });
36554
36555                 datepickerEl.attr(cameltoDash(key), 'watchData.' + key);
36556               }
36557             });
36558
36559             if (attrs.dateDisabled) {
36560               datepickerEl.attr('date-disabled', 'dateDisabled({ date: date, mode: mode })');
36561             }
36562
36563             angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle', 'showWeeks', 'startingDay', 'yearRows', 'yearColumns'], function(key) {
36564               if (angular.isDefined(attrs[key])) {
36565                 datepickerEl.attr(cameltoDash(key), attrs[key]);
36566               }
36567             });
36568
36569             if (attrs.customClass) {
36570               datepickerEl.attr('custom-class', 'customClass({ date: date, mode: mode })');
36571             }
36572
36573             if (!isHtml5DateInput) {
36574               // Internal API to maintain the correct ng-invalid-[key] class
36575               ngModel.$$parserName = 'date';
36576               ngModel.$validators.date = validator;
36577               ngModel.$parsers.unshift(parseDate);
36578               ngModel.$formatters.push(function(value) {
36579                 if (ngModel.$isEmpty(value)) {
36580                   scope.date = value;
36581                   return value;
36582                 }
36583                 scope.date = dateParser.fromTimezone(value, ngModelOptions.timezone);
36584                 return dateFilter(scope.date, dateFormat);
36585               });
36586             } else {
36587               ngModel.$formatters.push(function(value) {
36588                 scope.date = dateParser.fromTimezone(value, ngModelOptions.timezone);
36589                 return value;
36590               });
36591             }
36592
36593             // Detect changes in the view from the text box
36594             ngModel.$viewChangeListeners.push(function() {
36595               scope.date = parseDateString(ngModel.$viewValue);
36596             });
36597
36598             element.bind('keydown', inputKeydownBind);
36599
36600             $popup = $compile(popupEl)(scope);
36601             // Prevent jQuery cache memory leak (template is now redundant after linking)
36602             popupEl.remove();
36603
36604             if (appendToBody) {
36605               $document.find('body').append($popup);
36606             } else {
36607               element.after($popup);
36608             }
36609
36610             scope.$on('$destroy', function() {
36611               if (scope.isOpen === true) {
36612                 if (!$rootScope.$$phase) {
36613                   scope.$apply(function() {
36614                     scope.isOpen = false;
36615                   });
36616                 }
36617               }
36618
36619               $popup.remove();
36620               element.unbind('keydown', inputKeydownBind);
36621               $document.unbind('click', documentClickBind);
36622             });
36623           };
36624
36625           scope.getText = function(key) {
36626             return scope[key + 'Text'] || datepickerPopupConfig[key + 'Text'];
36627           };
36628
36629           scope.isDisabled = function(date) {
36630             if (date === 'today') {
36631               date = new Date();
36632             }
36633
36634             return scope.watchData.minDate && scope.compare(date, cache.minDate) < 0 ||
36635               scope.watchData.maxDate && scope.compare(date, cache.maxDate) > 0;
36636           };
36637
36638           scope.compare = function(date1, date2) {
36639             return new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
36640           };
36641
36642           // Inner change
36643           scope.dateSelection = function(dt) {
36644             if (angular.isDefined(dt)) {
36645               scope.date = dt;
36646             }
36647             var date = scope.date ? dateFilter(scope.date, dateFormat) : null; // Setting to NULL is necessary for form validators to function
36648             element.val(date);
36649             ngModel.$setViewValue(date);
36650
36651             if (closeOnDateSelection) {
36652               scope.isOpen = false;
36653               element[0].focus();
36654             }
36655           };
36656
36657           scope.keydown = function(evt) {
36658             if (evt.which === 27) {
36659               evt.stopPropagation();
36660               scope.isOpen = false;
36661               element[0].focus();
36662             }
36663           };
36664
36665           scope.select = function(date) {
36666             if (date === 'today') {
36667               var today = new Date();
36668               if (angular.isDate(scope.date)) {
36669                 date = new Date(scope.date);
36670                 date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate());
36671               } else {
36672                 date = new Date(today.setHours(0, 0, 0, 0));
36673               }
36674             }
36675             scope.dateSelection(date);
36676           };
36677
36678           scope.close = function() {
36679             scope.isOpen = false;
36680             element[0].focus();
36681           };
36682
36683           scope.disabled = angular.isDefined(attrs.disabled) || false;
36684           if (attrs.ngDisabled) {
36685             scope.$parent.$watch($parse(attrs.ngDisabled), function(disabled) {
36686               scope.disabled = disabled;
36687             });
36688           }
36689
36690           scope.$watch('isOpen', function(value) {
36691             if (value) {
36692               if (!scope.disabled) {
36693                 scope.position = appendToBody ? $position.offset(element) : $position.position(element);
36694                 scope.position.top = scope.position.top + element.prop('offsetHeight');
36695
36696                 $timeout(function() {
36697                   if (onOpenFocus) {
36698                     scope.$broadcast('uib:datepicker.focus');
36699                   }
36700                   $document.bind('click', documentClickBind);
36701                 }, 0, false);
36702               } else {
36703                 scope.isOpen = false;
36704               }
36705             } else {
36706               $document.unbind('click', documentClickBind);
36707             }
36708           });
36709
36710           function cameltoDash(string) {
36711             return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); });
36712           }
36713
36714           function parseDateString(viewValue) {
36715             var date = dateParser.parse(viewValue, dateFormat, scope.date);
36716             if (isNaN(date)) {
36717               for (var i = 0; i < altInputFormats.length; i++) {
36718                 date = dateParser.parse(viewValue, altInputFormats[i], scope.date);
36719                 if (!isNaN(date)) {
36720                   return date;
36721                 }
36722               }
36723             }
36724             return date;
36725           }
36726
36727           function parseDate(viewValue) {
36728             if (angular.isNumber(viewValue)) {
36729               // presumably timestamp to date object
36730               viewValue = new Date(viewValue);
36731             }
36732
36733             if (!viewValue) {
36734               return null;
36735             }
36736
36737             if (angular.isDate(viewValue) && !isNaN(viewValue)) {
36738               return viewValue;
36739             }
36740
36741             if (angular.isString(viewValue)) {
36742               var date = parseDateString(viewValue);
36743               if (!isNaN(date)) {
36744                 return dateParser.toTimezone(date, ngModelOptions.timezone);
36745               }
36746             }
36747
36748             return ngModel.$options && ngModel.$options.allowInvalid ? viewValue : undefined;
36749           }
36750
36751           function validator(modelValue, viewValue) {
36752             var value = modelValue || viewValue;
36753
36754             if (!attrs.ngRequired && !value) {
36755               return true;
36756             }
36757
36758             if (angular.isNumber(value)) {
36759               value = new Date(value);
36760             }
36761
36762             if (!value) {
36763               return true;
36764             }
36765
36766             if (angular.isDate(value) && !isNaN(value)) {
36767               return true;
36768             }
36769
36770             if (angular.isString(value)) {
36771               return !isNaN(parseDateString(viewValue));
36772             }
36773
36774             return false;
36775           }
36776
36777           function documentClickBind(event) {
36778             if (!scope.isOpen && scope.disabled) {
36779               return;
36780             }
36781
36782             var popup = $popup[0];
36783             var dpContainsTarget = element[0].contains(event.target);
36784             // The popup node may not be an element node
36785             // In some browsers (IE) only element nodes have the 'contains' function
36786             var popupContainsTarget = popup.contains !== undefined && popup.contains(event.target);
36787             if (scope.isOpen && !(dpContainsTarget || popupContainsTarget)) {
36788               scope.$apply(function() {
36789                 scope.isOpen = false;
36790               });
36791             }
36792           }
36793
36794           function inputKeydownBind(evt) {
36795             if (evt.which === 27 && scope.isOpen) {
36796               evt.preventDefault();
36797               evt.stopPropagation();
36798               scope.$apply(function() {
36799                 scope.isOpen = false;
36800               });
36801               element[0].focus();
36802             } else if (evt.which === 40 && !scope.isOpen) {
36803               evt.preventDefault();
36804               evt.stopPropagation();
36805               scope.$apply(function() {
36806                 scope.isOpen = true;
36807               });
36808             }
36809           }
36810         }])
36811
36812         .directive('uibDatepickerPopup', function() {
36813           return {
36814             require: ['ngModel', 'uibDatepickerPopup'],
36815             controller: 'UibDatepickerPopupController',
36816             scope: {
36817               isOpen: '=?',
36818               currentText: '@',
36819               clearText: '@',
36820               closeText: '@',
36821               dateDisabled: '&',
36822               customClass: '&'
36823             },
36824             link: function(scope, element, attrs, ctrls) {
36825               var ngModel = ctrls[0],
36826                 ctrl = ctrls[1];
36827
36828               ctrl.init(ngModel);
36829             }
36830           };
36831         })
36832
36833         .directive('uibDatepickerPopupWrap', function() {
36834           return {
36835             replace: true,
36836             transclude: true,
36837             templateUrl: function(element, attrs) {
36838               return attrs.templateUrl || 'uib/template/datepicker/popup.html';
36839             }
36840           };
36841         });
36842
36843         angular.module('ui.bootstrap.debounce', [])
36844         /**
36845          * A helper, internal service that debounces a function
36846          */
36847           .factory('$$debounce', ['$timeout', function($timeout) {
36848             return function(callback, debounceTime) {
36849               var timeoutPromise;
36850
36851               return function() {
36852                 var self = this;
36853                 var args = Array.prototype.slice.call(arguments);
36854                 if (timeoutPromise) {
36855                   $timeout.cancel(timeoutPromise);
36856                 }
36857
36858                 timeoutPromise = $timeout(function() {
36859                   callback.apply(self, args);
36860                 }, debounceTime);
36861               };
36862             };
36863           }]);
36864
36865         angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
36866
36867         .constant('uibDropdownConfig', {
36868           appendToOpenClass: 'uib-dropdown-open',
36869           openClass: 'open'
36870         })
36871
36872         .service('uibDropdownService', ['$document', '$rootScope', function($document, $rootScope) {
36873           var openScope = null;
36874
36875           this.open = function(dropdownScope) {
36876             if (!openScope) {
36877               $document.on('click', closeDropdown);
36878               $document.on('keydown', keybindFilter);
36879             }
36880
36881             if (openScope && openScope !== dropdownScope) {
36882               openScope.isOpen = false;
36883             }
36884
36885             openScope = dropdownScope;
36886           };
36887
36888           this.close = function(dropdownScope) {
36889             if (openScope === dropdownScope) {
36890               openScope = null;
36891               $document.off('click', closeDropdown);
36892               $document.off('keydown', keybindFilter);
36893             }
36894           };
36895
36896           var closeDropdown = function(evt) {
36897             // This method may still be called during the same mouse event that
36898             // unbound this event handler. So check openScope before proceeding.
36899             if (!openScope) { return; }
36900
36901             if (evt && openScope.getAutoClose() === 'disabled') { return; }
36902
36903             if (evt && evt.which === 3) { return; }
36904
36905             var toggleElement = openScope.getToggleElement();
36906             if (evt && toggleElement && toggleElement[0].contains(evt.target)) {
36907               return;
36908             }
36909
36910             var dropdownElement = openScope.getDropdownElement();
36911             if (evt && openScope.getAutoClose() === 'outsideClick' &&
36912               dropdownElement && dropdownElement[0].contains(evt.target)) {
36913               return;
36914             }
36915
36916             openScope.isOpen = false;
36917
36918             if (!$rootScope.$$phase) {
36919               openScope.$apply();
36920             }
36921           };
36922
36923           var keybindFilter = function(evt) {
36924             if (evt.which === 27) {
36925               openScope.focusToggleElement();
36926               closeDropdown();
36927             } else if (openScope.isKeynavEnabled() && [38, 40].indexOf(evt.which) !== -1 && openScope.isOpen) {
36928               evt.preventDefault();
36929               evt.stopPropagation();
36930               openScope.focusDropdownEntry(evt.which);
36931             }
36932           };
36933         }])
36934
36935         .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) {
36936           var self = this,
36937             scope = $scope.$new(), // create a child scope so we are not polluting original one
36938             templateScope,
36939             appendToOpenClass = dropdownConfig.appendToOpenClass,
36940             openClass = dropdownConfig.openClass,
36941             getIsOpen,
36942             setIsOpen = angular.noop,
36943             toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop,
36944             appendToBody = false,
36945             appendTo = null,
36946             keynavEnabled = false,
36947             selectedOption = null,
36948             body = $document.find('body');
36949
36950           $element.addClass('dropdown');
36951
36952           this.init = function() {
36953             if ($attrs.isOpen) {
36954               getIsOpen = $parse($attrs.isOpen);
36955               setIsOpen = getIsOpen.assign;
36956
36957               $scope.$watch(getIsOpen, function(value) {
36958                 scope.isOpen = !!value;
36959               });
36960             }
36961
36962             if (angular.isDefined($attrs.dropdownAppendTo)) {
36963               var appendToEl = $parse($attrs.dropdownAppendTo)(scope);
36964               if (appendToEl) {
36965                 appendTo = angular.element(appendToEl);
36966               }
36967             }
36968
36969             appendToBody = angular.isDefined($attrs.dropdownAppendToBody);
36970             keynavEnabled = angular.isDefined($attrs.keyboardNav);
36971
36972             if (appendToBody && !appendTo) {
36973               appendTo = body;
36974             }
36975
36976             if (appendTo && self.dropdownMenu) {
36977               appendTo.append(self.dropdownMenu);
36978               $element.on('$destroy', function handleDestroyEvent() {
36979                 self.dropdownMenu.remove();
36980               });
36981             }
36982           };
36983
36984           this.toggle = function(open) {
36985             return scope.isOpen = arguments.length ? !!open : !scope.isOpen;
36986           };
36987
36988           // Allow other directives to watch status
36989           this.isOpen = function() {
36990             return scope.isOpen;
36991           };
36992
36993           scope.getToggleElement = function() {
36994             return self.toggleElement;
36995           };
36996
36997           scope.getAutoClose = function() {
36998             return $attrs.autoClose || 'always'; //or 'outsideClick' or 'disabled'
36999           };
37000
37001           scope.getElement = function() {
37002             return $element;
37003           };
37004
37005           scope.isKeynavEnabled = function() {
37006             return keynavEnabled;
37007           };
37008
37009           scope.focusDropdownEntry = function(keyCode) {
37010             var elems = self.dropdownMenu ? //If append to body is used.
37011               angular.element(self.dropdownMenu).find('a') :
37012               $element.find('ul').eq(0).find('a');
37013
37014             switch (keyCode) {
37015               case 40: {
37016                 if (!angular.isNumber(self.selectedOption)) {
37017                   self.selectedOption = 0;
37018                 } else {
37019                   self.selectedOption = self.selectedOption === elems.length - 1 ?
37020                     self.selectedOption :
37021                     self.selectedOption + 1;
37022                 }
37023                 break;
37024               }
37025               case 38: {
37026                 if (!angular.isNumber(self.selectedOption)) {
37027                   self.selectedOption = elems.length - 1;
37028                 } else {
37029                   self.selectedOption = self.selectedOption === 0 ?
37030                     0 : self.selectedOption - 1;
37031                 }
37032                 break;
37033               }
37034             }
37035             elems[self.selectedOption].focus();
37036           };
37037
37038           scope.getDropdownElement = function() {
37039             return self.dropdownMenu;
37040           };
37041
37042           scope.focusToggleElement = function() {
37043             if (self.toggleElement) {
37044               self.toggleElement[0].focus();
37045             }
37046           };
37047
37048           scope.$watch('isOpen', function(isOpen, wasOpen) {
37049             if (appendTo && self.dropdownMenu) {
37050               var pos = $position.positionElements($element, self.dropdownMenu, 'bottom-left', true),
37051                 css,
37052                 rightalign;
37053
37054               css = {
37055                 top: pos.top + 'px',
37056                 display: isOpen ? 'block' : 'none'
37057               };
37058
37059               rightalign = self.dropdownMenu.hasClass('dropdown-menu-right');
37060               if (!rightalign) {
37061                 css.left = pos.left + 'px';
37062                 css.right = 'auto';
37063               } else {
37064                 css.left = 'auto';
37065                 css.right = window.innerWidth -
37066                   (pos.left + $element.prop('offsetWidth')) + 'px';
37067               }
37068
37069               // Need to adjust our positioning to be relative to the appendTo container
37070               // if it's not the body element
37071               if (!appendToBody) {
37072                 var appendOffset = $position.offset(appendTo);
37073
37074                 css.top = pos.top - appendOffset.top + 'px';
37075
37076                 if (!rightalign) {
37077                   css.left = pos.left - appendOffset.left + 'px';
37078                 } else {
37079                   css.right = window.innerWidth -
37080                     (pos.left - appendOffset.left + $element.prop('offsetWidth')) + 'px';
37081                 }
37082               }
37083
37084               self.dropdownMenu.css(css);
37085             }
37086
37087             var openContainer = appendTo ? appendTo : $element;
37088
37089             $animate[isOpen ? 'addClass' : 'removeClass'](openContainer, appendTo ? appendToOpenClass : openClass).then(function() {
37090               if (angular.isDefined(isOpen) && isOpen !== wasOpen) {
37091                 toggleInvoker($scope, { open: !!isOpen });
37092               }
37093             });
37094
37095             if (isOpen) {
37096               if (self.dropdownMenuTemplateUrl) {
37097                 $templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) {
37098                   templateScope = scope.$new();
37099                   $compile(tplContent.trim())(templateScope, function(dropdownElement) {
37100                     var newEl = dropdownElement;
37101                     self.dropdownMenu.replaceWith(newEl);
37102                     self.dropdownMenu = newEl;
37103                   });
37104                 });
37105               }
37106
37107               scope.focusToggleElement();
37108               uibDropdownService.open(scope);
37109             } else {
37110               if (self.dropdownMenuTemplateUrl) {
37111                 if (templateScope) {
37112                   templateScope.$destroy();
37113                 }
37114                 var newEl = angular.element('<ul class="dropdown-menu"></ul>');
37115                 self.dropdownMenu.replaceWith(newEl);
37116                 self.dropdownMenu = newEl;
37117               }
37118
37119               uibDropdownService.close(scope);
37120               self.selectedOption = null;
37121             }
37122
37123             if (angular.isFunction(setIsOpen)) {
37124               setIsOpen($scope, isOpen);
37125             }
37126           });
37127
37128           $scope.$on('$locationChangeSuccess', function() {
37129             if (scope.getAutoClose() !== 'disabled') {
37130               scope.isOpen = false;
37131             }
37132           });
37133         }])
37134
37135         .directive('uibDropdown', function() {
37136           return {
37137             controller: 'UibDropdownController',
37138             link: function(scope, element, attrs, dropdownCtrl) {
37139               dropdownCtrl.init();
37140             }
37141           };
37142         })
37143
37144         .directive('uibDropdownMenu', function() {
37145           return {
37146             restrict: 'A',
37147             require: '?^uibDropdown',
37148             link: function(scope, element, attrs, dropdownCtrl) {
37149               if (!dropdownCtrl || angular.isDefined(attrs.dropdownNested)) {
37150                 return;
37151               }
37152
37153               element.addClass('dropdown-menu');
37154
37155               var tplUrl = attrs.templateUrl;
37156               if (tplUrl) {
37157                 dropdownCtrl.dropdownMenuTemplateUrl = tplUrl;
37158               }
37159
37160               if (!dropdownCtrl.dropdownMenu) {
37161                 dropdownCtrl.dropdownMenu = element;
37162               }
37163             }
37164           };
37165         })
37166
37167         .directive('uibDropdownToggle', function() {
37168           return {
37169             require: '?^uibDropdown',
37170             link: function(scope, element, attrs, dropdownCtrl) {
37171               if (!dropdownCtrl) {
37172                 return;
37173               }
37174
37175               element.addClass('dropdown-toggle');
37176
37177               dropdownCtrl.toggleElement = element;
37178
37179               var toggleDropdown = function(event) {
37180                 event.preventDefault();
37181
37182                 if (!element.hasClass('disabled') && !attrs.disabled) {
37183                   scope.$apply(function() {
37184                     dropdownCtrl.toggle();
37185                   });
37186                 }
37187               };
37188
37189               element.bind('click', toggleDropdown);
37190
37191               // WAI-ARIA
37192               element.attr({ 'aria-haspopup': true, 'aria-expanded': false });
37193               scope.$watch(dropdownCtrl.isOpen, function(isOpen) {
37194                 element.attr('aria-expanded', !!isOpen);
37195               });
37196
37197               scope.$on('$destroy', function() {
37198                 element.unbind('click', toggleDropdown);
37199               });
37200             }
37201           };
37202         });
37203
37204         angular.module('ui.bootstrap.stackedMap', [])
37205         /**
37206          * A helper, internal data structure that acts as a map but also allows getting / removing
37207          * elements in the LIFO order
37208          */
37209           .factory('$$stackedMap', function() {
37210             return {
37211               createNew: function() {
37212                 var stack = [];
37213
37214                 return {
37215                   add: function(key, value) {
37216                     stack.push({
37217                       key: key,
37218                       value: value
37219                     });
37220                   },
37221                   get: function(key) {
37222                     for (var i = 0; i < stack.length; i++) {
37223                       if (key === stack[i].key) {
37224                         return stack[i];
37225                       }
37226                     }
37227                   },
37228                   keys: function() {
37229                     var keys = [];
37230                     for (var i = 0; i < stack.length; i++) {
37231                       keys.push(stack[i].key);
37232                     }
37233                     return keys;
37234                   },
37235                   top: function() {
37236                     return stack[stack.length - 1];
37237                   },
37238                   remove: function(key) {
37239                     var idx = -1;
37240                     for (var i = 0; i < stack.length; i++) {
37241                       if (key === stack[i].key) {
37242                         idx = i;
37243                         break;
37244                       }
37245                     }
37246                     return stack.splice(idx, 1)[0];
37247                   },
37248                   removeTop: function() {
37249                     return stack.splice(stack.length - 1, 1)[0];
37250                   },
37251                   length: function() {
37252                     return stack.length;
37253                   }
37254                 };
37255               }
37256             };
37257           });
37258         angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
37259         /**
37260          * A helper, internal data structure that stores all references attached to key
37261          */
37262           .factory('$$multiMap', function() {
37263             return {
37264               createNew: function() {
37265                 var map = {};
37266
37267                 return {
37268                   entries: function() {
37269                     return Object.keys(map).map(function(key) {
37270                       return {
37271                         key: key,
37272                         value: map[key]
37273                       };
37274                     });
37275                   },
37276                   get: function(key) {
37277                     return map[key];
37278                   },
37279                   hasKey: function(key) {
37280                     return !!map[key];
37281                   },
37282                   keys: function() {
37283                     return Object.keys(map);
37284                   },
37285                   put: function(key, value) {
37286                     if (!map[key]) {
37287                       map[key] = [];
37288                     }
37289
37290                     map[key].push(value);
37291                   },
37292                   remove: function(key, value) {
37293                     var values = map[key];
37294
37295                     if (!values) {
37296                       return;
37297                     }
37298
37299                     var idx = values.indexOf(value);
37300
37301                     if (idx !== -1) {
37302                       values.splice(idx, 1);
37303                     }
37304
37305                     if (!values.length) {
37306                       delete map[key];
37307                     }
37308                   }
37309                 };
37310               }
37311             };
37312           })
37313
37314         /**
37315          * Pluggable resolve mechanism for the modal resolve resolution
37316          * Supports UI Router's $resolve service
37317          */
37318           .provider('$uibResolve', function() {
37319             var resolve = this;
37320             this.resolver = null;
37321
37322             this.setResolver = function(resolver) {
37323               this.resolver = resolver;
37324             };
37325
37326             this.$get = ['$injector', '$q', function($injector, $q) {
37327               var resolver = resolve.resolver ? $injector.get(resolve.resolver) : null;
37328               return {
37329                 resolve: function(invocables, locals, parent, self) {
37330                   if (resolver) {
37331                     return resolver.resolve(invocables, locals, parent, self);
37332                   }
37333
37334                   var promises = [];
37335
37336                   angular.forEach(invocables, function(value) {
37337                     if (angular.isFunction(value) || angular.isArray(value)) {
37338                       promises.push($q.resolve($injector.invoke(value)));
37339                     } else if (angular.isString(value)) {
37340                       promises.push($q.resolve($injector.get(value)));
37341                     } else {
37342                       promises.push($q.resolve(value));
37343                     }
37344                   });
37345
37346                   return $q.all(promises).then(function(resolves) {
37347                     var resolveObj = {};
37348                     var resolveIter = 0;
37349                     angular.forEach(invocables, function(value, key) {
37350                       resolveObj[key] = resolves[resolveIter++];
37351                     });
37352
37353                     return resolveObj;
37354                   });
37355                 }
37356               };
37357             }];
37358           })
37359
37360         /**
37361          * A helper directive for the $modal service. It creates a backdrop element.
37362          */
37363           .directive('uibModalBackdrop', ['$animateCss', '$injector', '$uibModalStack',
37364           function($animateCss, $injector, $modalStack) {
37365             return {
37366               replace: true,
37367               templateUrl: 'uib/template/modal/backdrop.html',
37368               compile: function(tElement, tAttrs) {
37369                 tElement.addClass(tAttrs.backdropClass);
37370                 return linkFn;
37371               }
37372             };
37373
37374             function linkFn(scope, element, attrs) {
37375               if (attrs.modalInClass) {
37376                 $animateCss(element, {
37377                   addClass: attrs.modalInClass
37378                 }).start();
37379
37380                 scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
37381                   var done = setIsAsync();
37382                   if (scope.modalOptions.animation) {
37383                     $animateCss(element, {
37384                       removeClass: attrs.modalInClass
37385                     }).start().then(done);
37386                   } else {
37387                     done();
37388                   }
37389                 });
37390               }
37391             }
37392           }])
37393
37394           .directive('uibModalWindow', ['$uibModalStack', '$q', '$animate', '$animateCss', '$document',
37395           function($modalStack, $q, $animate, $animateCss, $document) {
37396             return {
37397               scope: {
37398                 index: '@'
37399               },
37400               replace: true,
37401               transclude: true,
37402               templateUrl: function(tElement, tAttrs) {
37403                 return tAttrs.templateUrl || 'uib/template/modal/window.html';
37404               },
37405               link: function(scope, element, attrs) {
37406                 element.addClass(attrs.windowClass || '');
37407                 element.addClass(attrs.windowTopClass || '');
37408                 scope.size = attrs.size;
37409
37410                 scope.close = function(evt) {
37411                   var modal = $modalStack.getTop();
37412                   if (modal && modal.value.backdrop &&
37413                     modal.value.backdrop !== 'static' &&
37414                     evt.target === evt.currentTarget) {
37415                     evt.preventDefault();
37416                     evt.stopPropagation();
37417                     $modalStack.dismiss(modal.key, 'backdrop click');
37418                   }
37419                 };
37420
37421                 // moved from template to fix issue #2280
37422                 element.on('click', scope.close);
37423
37424                 // This property is only added to the scope for the purpose of detecting when this directive is rendered.
37425                 // We can detect that by using this property in the template associated with this directive and then use
37426                 // {@link Attribute#$observe} on it. For more details please see {@link TableColumnResize}.
37427                 scope.$isRendered = true;
37428
37429                 // Deferred object that will be resolved when this modal is render.
37430                 var modalRenderDeferObj = $q.defer();
37431                 // Observe function will be called on next digest cycle after compilation, ensuring that the DOM is ready.
37432                 // In order to use this way of finding whether DOM is ready, we need to observe a scope property used in modal's template.
37433                 attrs.$observe('modalRender', function(value) {
37434                   if (value === 'true') {
37435                     modalRenderDeferObj.resolve();
37436                   }
37437                 });
37438
37439                 modalRenderDeferObj.promise.then(function() {
37440                   var animationPromise = null;
37441
37442                   if (attrs.modalInClass) {
37443                     animationPromise = $animateCss(element, {
37444                       addClass: attrs.modalInClass
37445                     }).start();
37446
37447                     scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
37448                       var done = setIsAsync();
37449                       if ($animateCss) {
37450                         $animateCss(element, {
37451                           removeClass: attrs.modalInClass
37452                         }).start().then(done);
37453                       } else {
37454                         $animate.removeClass(element, attrs.modalInClass).then(done);
37455                       }
37456                     });
37457                   }
37458
37459
37460                   $q.when(animationPromise).then(function() {
37461                     /**
37462                      * If something within the freshly-opened modal already has focus (perhaps via a
37463                      * directive that causes focus). then no need to try and focus anything.
37464                      */
37465                     if (!($document[0].activeElement && element[0].contains($document[0].activeElement))) {
37466                       var inputWithAutofocus = element[0].querySelector('[autofocus]');
37467                       /**
37468                        * Auto-focusing of a freshly-opened modal element causes any child elements
37469                        * with the autofocus attribute to lose focus. This is an issue on touch
37470                        * based devices which will show and then hide the onscreen keyboard.
37471                        * Attempts to refocus the autofocus element via JavaScript will not reopen
37472                        * the onscreen keyboard. Fixed by updated the focusing logic to only autofocus
37473                        * the modal element if the modal does not contain an autofocus element.
37474                        */
37475                       if (inputWithAutofocus) {
37476                         inputWithAutofocus.focus();
37477                       } else {
37478                         element[0].focus();
37479                       }
37480                     }
37481                   });
37482
37483                   // Notify {@link $modalStack} that modal is rendered.
37484                   var modal = $modalStack.getTop();
37485                   if (modal) {
37486                     $modalStack.modalRendered(modal.key);
37487                   }
37488                 });
37489               }
37490             };
37491           }])
37492
37493           .directive('uibModalAnimationClass', function() {
37494             return {
37495               compile: function(tElement, tAttrs) {
37496                 if (tAttrs.modalAnimation) {
37497                   tElement.addClass(tAttrs.uibModalAnimationClass);
37498                 }
37499               }
37500             };
37501           })
37502
37503           .directive('uibModalTransclude', function() {
37504             return {
37505               link: function(scope, element, attrs, controller, transclude) {
37506                 transclude(scope.$parent, function(clone) {
37507                   element.empty();
37508                   element.append(clone);
37509                 });
37510               }
37511             };
37512           })
37513
37514           .factory('$uibModalStack', ['$animate', '$animateCss', '$document',
37515             '$compile', '$rootScope', '$q', '$$multiMap', '$$stackedMap',
37516             function($animate, $animateCss, $document, $compile, $rootScope, $q, $$multiMap, $$stackedMap) {
37517               var OPENED_MODAL_CLASS = 'modal-open';
37518
37519               var backdropDomEl, backdropScope;
37520               var openedWindows = $$stackedMap.createNew();
37521               var openedClasses = $$multiMap.createNew();
37522               var $modalStack = {
37523                 NOW_CLOSING_EVENT: 'modal.stack.now-closing'
37524               };
37525
37526               //Modal focus behavior
37527               var focusableElementList;
37528               var focusIndex = 0;
37529               var tababbleSelector = 'a[href], area[href], input:not([disabled]), ' +
37530                 'button:not([disabled]),select:not([disabled]), textarea:not([disabled]), ' +
37531                 'iframe, object, embed, *[tabindex], *[contenteditable=true]';
37532
37533               function backdropIndex() {
37534                 var topBackdropIndex = -1;
37535                 var opened = openedWindows.keys();
37536                 for (var i = 0; i < opened.length; i++) {
37537                   if (openedWindows.get(opened[i]).value.backdrop) {
37538                     topBackdropIndex = i;
37539                   }
37540                 }
37541                 return topBackdropIndex;
37542               }
37543
37544               $rootScope.$watch(backdropIndex, function(newBackdropIndex) {
37545                 if (backdropScope) {
37546                   backdropScope.index = newBackdropIndex;
37547                 }
37548               });
37549
37550               function removeModalWindow(modalInstance, elementToReceiveFocus) {
37551                 var modalWindow = openedWindows.get(modalInstance).value;
37552                 var appendToElement = modalWindow.appendTo;
37553
37554                 //clean up the stack
37555                 openedWindows.remove(modalInstance);
37556
37557                 removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
37558                   var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS;
37559                   openedClasses.remove(modalBodyClass, modalInstance);
37560                   appendToElement.toggleClass(modalBodyClass, openedClasses.hasKey(modalBodyClass));
37561                   toggleTopWindowClass(true);
37562                 });
37563                 checkRemoveBackdrop();
37564
37565                 //move focus to specified element if available, or else to body
37566                 if (elementToReceiveFocus && elementToReceiveFocus.focus) {
37567                   elementToReceiveFocus.focus();
37568                 } else if (appendToElement.focus) {
37569                   appendToElement.focus();
37570                 }
37571               }
37572
37573               // Add or remove "windowTopClass" from the top window in the stack
37574               function toggleTopWindowClass(toggleSwitch) {
37575                 var modalWindow;
37576
37577                 if (openedWindows.length() > 0) {
37578                   modalWindow = openedWindows.top().value;
37579                   modalWindow.modalDomEl.toggleClass(modalWindow.windowTopClass || '', toggleSwitch);
37580                 }
37581               }
37582
37583               function checkRemoveBackdrop() {
37584                 //remove backdrop if no longer needed
37585                 if (backdropDomEl && backdropIndex() === -1) {
37586                   var backdropScopeRef = backdropScope;
37587                   removeAfterAnimate(backdropDomEl, backdropScope, function() {
37588                     backdropScopeRef = null;
37589                   });
37590                   backdropDomEl = undefined;
37591                   backdropScope = undefined;
37592                 }
37593               }
37594
37595               function removeAfterAnimate(domEl, scope, done, closedDeferred) {
37596                 var asyncDeferred;
37597                 var asyncPromise = null;
37598                 var setIsAsync = function() {
37599                   if (!asyncDeferred) {
37600                     asyncDeferred = $q.defer();
37601                     asyncPromise = asyncDeferred.promise;
37602                   }
37603
37604                   return function asyncDone() {
37605                     asyncDeferred.resolve();
37606                   };
37607                 };
37608                 scope.$broadcast($modalStack.NOW_CLOSING_EVENT, setIsAsync);
37609
37610                 // Note that it's intentional that asyncPromise might be null.
37611                 // That's when setIsAsync has not been called during the
37612                 // NOW_CLOSING_EVENT broadcast.
37613                 return $q.when(asyncPromise).then(afterAnimating);
37614
37615                 function afterAnimating() {
37616                   if (afterAnimating.done) {
37617                     return;
37618                   }
37619                   afterAnimating.done = true;
37620
37621                   $animateCss(domEl, {
37622                     event: 'leave'
37623                   }).start().then(function() {
37624                     domEl.remove();
37625                     if (closedDeferred) {
37626                       closedDeferred.resolve();
37627                     }
37628                   });
37629
37630                   scope.$destroy();
37631                   if (done) {
37632                     done();
37633                   }
37634                 }
37635               }
37636
37637               $document.on('keydown', keydownListener);
37638
37639               $rootScope.$on('$destroy', function() {
37640                 $document.off('keydown', keydownListener);
37641               });
37642
37643               function keydownListener(evt) {
37644                 if (evt.isDefaultPrevented()) {
37645                   return evt;
37646                 }
37647
37648                 var modal = openedWindows.top();
37649                 if (modal) {
37650                   switch (evt.which) {
37651                     case 27: {
37652                       if (modal.value.keyboard) {
37653                         evt.preventDefault();
37654                         $rootScope.$apply(function() {
37655                           $modalStack.dismiss(modal.key, 'escape key press');
37656                         });
37657                       }
37658                       break;
37659                     }
37660                     case 9: {
37661                       $modalStack.loadFocusElementList(modal);
37662                       var focusChanged = false;
37663                       if (evt.shiftKey) {
37664                         if ($modalStack.isFocusInFirstItem(evt)) {
37665                           focusChanged = $modalStack.focusLastFocusableElement();
37666                         }
37667                       } else {
37668                         if ($modalStack.isFocusInLastItem(evt)) {
37669                           focusChanged = $modalStack.focusFirstFocusableElement();
37670                         }
37671                       }
37672
37673                       if (focusChanged) {
37674                         evt.preventDefault();
37675                         evt.stopPropagation();
37676                       }
37677                       break;
37678                     }
37679                   }
37680                 }
37681               }
37682
37683               $modalStack.open = function(modalInstance, modal) {
37684                 var modalOpener = $document[0].activeElement,
37685                   modalBodyClass = modal.openedClass || OPENED_MODAL_CLASS;
37686
37687                 toggleTopWindowClass(false);
37688
37689                 openedWindows.add(modalInstance, {
37690                   deferred: modal.deferred,
37691                   renderDeferred: modal.renderDeferred,
37692                   closedDeferred: modal.closedDeferred,
37693                   modalScope: modal.scope,
37694                   backdrop: modal.backdrop,
37695                   keyboard: modal.keyboard,
37696                   openedClass: modal.openedClass,
37697                   windowTopClass: modal.windowTopClass,
37698                   animation: modal.animation,
37699                   appendTo: modal.appendTo
37700                 });
37701
37702                 openedClasses.put(modalBodyClass, modalInstance);
37703
37704                 var appendToElement = modal.appendTo,
37705                     currBackdropIndex = backdropIndex();
37706
37707                 if (!appendToElement.length) {
37708                   throw new Error('appendTo element not found. Make sure that the element passed is in DOM.');
37709                 }
37710
37711                 if (currBackdropIndex >= 0 && !backdropDomEl) {
37712                   backdropScope = $rootScope.$new(true);
37713                   backdropScope.modalOptions = modal;
37714                   backdropScope.index = currBackdropIndex;
37715                   backdropDomEl = angular.element('<div uib-modal-backdrop="modal-backdrop"></div>');
37716                   backdropDomEl.attr('backdrop-class', modal.backdropClass);
37717                   if (modal.animation) {
37718                     backdropDomEl.attr('modal-animation', 'true');
37719                   }
37720                   $compile(backdropDomEl)(backdropScope);
37721                   $animate.enter(backdropDomEl, appendToElement);
37722                 }
37723
37724                 var angularDomEl = angular.element('<div uib-modal-window="modal-window"></div>');
37725                 angularDomEl.attr({
37726                   'template-url': modal.windowTemplateUrl,
37727                   'window-class': modal.windowClass,
37728                   'window-top-class': modal.windowTopClass,
37729                   'size': modal.size,
37730                   'index': openedWindows.length() - 1,
37731                   'animate': 'animate'
37732                 }).html(modal.content);
37733                 if (modal.animation) {
37734                   angularDomEl.attr('modal-animation', 'true');
37735                 }
37736
37737                 $animate.enter(angularDomEl, appendToElement)
37738                   .then(function() {
37739                     $compile(angularDomEl)(modal.scope);
37740                     $animate.addClass(appendToElement, modalBodyClass);
37741                   });
37742
37743                 openedWindows.top().value.modalDomEl = angularDomEl;
37744                 openedWindows.top().value.modalOpener = modalOpener;
37745
37746                 $modalStack.clearFocusListCache();
37747               };
37748
37749               function broadcastClosing(modalWindow, resultOrReason, closing) {
37750                 return !modalWindow.value.modalScope.$broadcast('modal.closing', resultOrReason, closing).defaultPrevented;
37751               }
37752
37753               $modalStack.close = function(modalInstance, result) {
37754                 var modalWindow = openedWindows.get(modalInstance);
37755                 if (modalWindow && broadcastClosing(modalWindow, result, true)) {
37756                   modalWindow.value.modalScope.$$uibDestructionScheduled = true;
37757                   modalWindow.value.deferred.resolve(result);
37758                   removeModalWindow(modalInstance, modalWindow.value.modalOpener);
37759                   return true;
37760                 }
37761                 return !modalWindow;
37762               };
37763
37764               $modalStack.dismiss = function(modalInstance, reason) {
37765                 var modalWindow = openedWindows.get(modalInstance);
37766                 if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
37767                   modalWindow.value.modalScope.$$uibDestructionScheduled = true;
37768                   modalWindow.value.deferred.reject(reason);
37769                   removeModalWindow(modalInstance, modalWindow.value.modalOpener);
37770                   return true;
37771                 }
37772                 return !modalWindow;
37773               };
37774
37775               $modalStack.dismissAll = function(reason) {
37776                 var topModal = this.getTop();
37777                 while (topModal && this.dismiss(topModal.key, reason)) {
37778                   topModal = this.getTop();
37779                 }
37780               };
37781
37782               $modalStack.getTop = function() {
37783                 return openedWindows.top();
37784               };
37785
37786               $modalStack.modalRendered = function(modalInstance) {
37787                 var modalWindow = openedWindows.get(modalInstance);
37788                 if (modalWindow) {
37789                   modalWindow.value.renderDeferred.resolve();
37790                 }
37791               };
37792
37793               $modalStack.focusFirstFocusableElement = function() {
37794                 if (focusableElementList.length > 0) {
37795                   focusableElementList[0].focus();
37796                   return true;
37797                 }
37798                 return false;
37799               };
37800               $modalStack.focusLastFocusableElement = function() {
37801                 if (focusableElementList.length > 0) {
37802                   focusableElementList[focusableElementList.length - 1].focus();
37803                   return true;
37804                 }
37805                 return false;
37806               };
37807
37808               $modalStack.isFocusInFirstItem = function(evt) {
37809                 if (focusableElementList.length > 0) {
37810                   return (evt.target || evt.srcElement) === focusableElementList[0];
37811                 }
37812                 return false;
37813               };
37814
37815               $modalStack.isFocusInLastItem = function(evt) {
37816                 if (focusableElementList.length > 0) {
37817                   return (evt.target || evt.srcElement) === focusableElementList[focusableElementList.length - 1];
37818                 }
37819                 return false;
37820               };
37821
37822               $modalStack.clearFocusListCache = function() {
37823                 focusableElementList = [];
37824                 focusIndex = 0;
37825               };
37826
37827               $modalStack.loadFocusElementList = function(modalWindow) {
37828                 if (focusableElementList === undefined || !focusableElementList.length) {
37829                   if (modalWindow) {
37830                     var modalDomE1 = modalWindow.value.modalDomEl;
37831                     if (modalDomE1 && modalDomE1.length) {
37832                       focusableElementList = modalDomE1[0].querySelectorAll(tababbleSelector);
37833                     }
37834                   }
37835                 }
37836               };
37837
37838               return $modalStack;
37839             }])
37840
37841           .provider('$uibModal', function() {
37842             var $modalProvider = {
37843               options: {
37844                 animation: true,
37845                 backdrop: true, //can also be false or 'static'
37846                 keyboard: true
37847               },
37848               $get: ['$rootScope', '$q', '$document', '$templateRequest', '$controller', '$uibResolve', '$uibModalStack',
37849                 function ($rootScope, $q, $document, $templateRequest, $controller, $uibResolve, $modalStack) {
37850                   var $modal = {};
37851
37852                   function getTemplatePromise(options) {
37853                     return options.template ? $q.when(options.template) :
37854                       $templateRequest(angular.isFunction(options.templateUrl) ?
37855                         options.templateUrl() : options.templateUrl);
37856                   }
37857
37858                   var promiseChain = null;
37859                   $modal.getPromiseChain = function() {
37860                     return promiseChain;
37861                   };
37862
37863                   $modal.open = function(modalOptions) {
37864                     var modalResultDeferred = $q.defer();
37865                     var modalOpenedDeferred = $q.defer();
37866                     var modalClosedDeferred = $q.defer();
37867                     var modalRenderDeferred = $q.defer();
37868
37869                     //prepare an instance of a modal to be injected into controllers and returned to a caller
37870                     var modalInstance = {
37871                       result: modalResultDeferred.promise,
37872                       opened: modalOpenedDeferred.promise,
37873                       closed: modalClosedDeferred.promise,
37874                       rendered: modalRenderDeferred.promise,
37875                       close: function (result) {
37876                         return $modalStack.close(modalInstance, result);
37877                       },
37878                       dismiss: function (reason) {
37879                         return $modalStack.dismiss(modalInstance, reason);
37880                       }
37881                     };
37882
37883                     //merge and clean up options
37884                     modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
37885                     modalOptions.resolve = modalOptions.resolve || {};
37886                     modalOptions.appendTo = modalOptions.appendTo || $document.find('body').eq(0);
37887
37888                     //verify options
37889                     if (!modalOptions.template && !modalOptions.templateUrl) {
37890                       throw new Error('One of template or templateUrl options is required.');
37891                     }
37892
37893                     var templateAndResolvePromise =
37894                       $q.all([getTemplatePromise(modalOptions), $uibResolve.resolve(modalOptions.resolve, {}, null, null)]);
37895
37896                     function resolveWithTemplate() {
37897                       return templateAndResolvePromise;
37898                     }
37899
37900                     // Wait for the resolution of the existing promise chain.
37901                     // Then switch to our own combined promise dependency (regardless of how the previous modal fared).
37902                     // Then add to $modalStack and resolve opened.
37903                     // Finally clean up the chain variable if no subsequent modal has overwritten it.
37904                     var samePromise;
37905                     samePromise = promiseChain = $q.all([promiseChain])
37906                       .then(resolveWithTemplate, resolveWithTemplate)
37907                       .then(function resolveSuccess(tplAndVars) {
37908                         var providedScope = modalOptions.scope || $rootScope;
37909
37910                         var modalScope = providedScope.$new();
37911                         modalScope.$close = modalInstance.close;
37912                         modalScope.$dismiss = modalInstance.dismiss;
37913
37914                         modalScope.$on('$destroy', function() {
37915                           if (!modalScope.$$uibDestructionScheduled) {
37916                             modalScope.$dismiss('$uibUnscheduledDestruction');
37917                           }
37918                         });
37919
37920                         var ctrlInstance, ctrlLocals = {};
37921
37922                         //controllers
37923                         if (modalOptions.controller) {
37924                           ctrlLocals.$scope = modalScope;
37925                           ctrlLocals.$uibModalInstance = modalInstance;
37926                           angular.forEach(tplAndVars[1], function(value, key) {
37927                             ctrlLocals[key] = value;
37928                           });
37929
37930                           ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
37931                           if (modalOptions.controllerAs) {
37932                             if (modalOptions.bindToController) {
37933                               ctrlInstance.$close = modalScope.$close;
37934                               ctrlInstance.$dismiss = modalScope.$dismiss;
37935                               angular.extend(ctrlInstance, providedScope);
37936                             }
37937
37938                             modalScope[modalOptions.controllerAs] = ctrlInstance;
37939                           }
37940                         }
37941
37942                         $modalStack.open(modalInstance, {
37943                           scope: modalScope,
37944                           deferred: modalResultDeferred,
37945                           renderDeferred: modalRenderDeferred,
37946                           closedDeferred: modalClosedDeferred,
37947                           content: tplAndVars[0],
37948                           animation: modalOptions.animation,
37949                           backdrop: modalOptions.backdrop,
37950                           keyboard: modalOptions.keyboard,
37951                           backdropClass: modalOptions.backdropClass,
37952                           windowTopClass: modalOptions.windowTopClass,
37953                           windowClass: modalOptions.windowClass,
37954                           windowTemplateUrl: modalOptions.windowTemplateUrl,
37955                           size: modalOptions.size,
37956                           openedClass: modalOptions.openedClass,
37957                           appendTo: modalOptions.appendTo
37958                         });
37959                         modalOpenedDeferred.resolve(true);
37960
37961                     }, function resolveError(reason) {
37962                       modalOpenedDeferred.reject(reason);
37963                       modalResultDeferred.reject(reason);
37964                     })['finally'](function() {
37965                       if (promiseChain === samePromise) {
37966                         promiseChain = null;
37967                       }
37968                     });
37969
37970                     return modalInstance;
37971                   };
37972
37973                   return $modal;
37974                 }
37975               ]
37976             };
37977
37978             return $modalProvider;
37979           });
37980
37981         angular.module('ui.bootstrap.paging', [])
37982         /**
37983          * Helper internal service for generating common controller code between the
37984          * pager and pagination components
37985          */
37986         .factory('uibPaging', ['$parse', function($parse) {
37987           return {
37988             create: function(ctrl, $scope, $attrs) {
37989               ctrl.setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
37990               ctrl.ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl
37991
37992               ctrl.init = function(ngModelCtrl, config) {
37993                 ctrl.ngModelCtrl = ngModelCtrl;
37994                 ctrl.config = config;
37995
37996                 ngModelCtrl.$render = function() {
37997                   ctrl.render();
37998                 };
37999
38000                 if ($attrs.itemsPerPage) {
38001                   $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
38002                     ctrl.itemsPerPage = parseInt(value, 10);
38003                     $scope.totalPages = ctrl.calculateTotalPages();
38004                     ctrl.updatePage();
38005                   });
38006                 } else {
38007                   ctrl.itemsPerPage = config.itemsPerPage;
38008                 }
38009
38010                 $scope.$watch('totalItems', function(newTotal, oldTotal) {
38011                   if (angular.isDefined(newTotal) || newTotal !== oldTotal) {
38012                     $scope.totalPages = ctrl.calculateTotalPages();
38013                     ctrl.updatePage();
38014                   }
38015                 });
38016               };
38017
38018               ctrl.calculateTotalPages = function() {
38019                 var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage);
38020                 return Math.max(totalPages || 0, 1);
38021               };
38022
38023               ctrl.render = function() {
38024                 $scope.page = parseInt(ctrl.ngModelCtrl.$viewValue, 10) || 1;
38025               };
38026
38027               $scope.selectPage = function(page, evt) {
38028                 if (evt) {
38029                   evt.preventDefault();
38030                 }
38031
38032                 var clickAllowed = !$scope.ngDisabled || !evt;
38033                 if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) {
38034                   if (evt && evt.target) {
38035                     evt.target.blur();
38036                   }
38037                   ctrl.ngModelCtrl.$setViewValue(page);
38038                   ctrl.ngModelCtrl.$render();
38039                 }
38040               };
38041
38042               $scope.getText = function(key) {
38043                 return $scope[key + 'Text'] || ctrl.config[key + 'Text'];
38044               };
38045
38046               $scope.noPrevious = function() {
38047                 return $scope.page === 1;
38048               };
38049
38050               $scope.noNext = function() {
38051                 return $scope.page === $scope.totalPages;
38052               };
38053
38054               ctrl.updatePage = function() {
38055                 ctrl.setNumPages($scope.$parent, $scope.totalPages); // Readonly variable
38056
38057                 if ($scope.page > $scope.totalPages) {
38058                   $scope.selectPage($scope.totalPages);
38059                 } else {
38060                   ctrl.ngModelCtrl.$render();
38061                 }
38062               };
38063             }
38064           };
38065         }]);
38066
38067         angular.module('ui.bootstrap.pager', ['ui.bootstrap.paging'])
38068
38069         .controller('UibPagerController', ['$scope', '$attrs', 'uibPaging', 'uibPagerConfig', function($scope, $attrs, uibPaging, uibPagerConfig) {
38070           $scope.align = angular.isDefined($attrs.align) ? $scope.$parent.$eval($attrs.align) : uibPagerConfig.align;
38071
38072           uibPaging.create(this, $scope, $attrs);
38073         }])
38074
38075         .constant('uibPagerConfig', {
38076           itemsPerPage: 10,
38077           previousText: '« Previous',
38078           nextText: 'Next »',
38079           align: true
38080         })
38081
38082         .directive('uibPager', ['uibPagerConfig', function(uibPagerConfig) {
38083           return {
38084             scope: {
38085               totalItems: '=',
38086               previousText: '@',
38087               nextText: '@',
38088               ngDisabled: '='
38089             },
38090             require: ['uibPager', '?ngModel'],
38091             controller: 'UibPagerController',
38092             controllerAs: 'pager',
38093             templateUrl: function(element, attrs) {
38094               return attrs.templateUrl || 'uib/template/pager/pager.html';
38095             },
38096             replace: true,
38097             link: function(scope, element, attrs, ctrls) {
38098               var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
38099
38100               if (!ngModelCtrl) {
38101                 return; // do nothing if no ng-model
38102               }
38103
38104               paginationCtrl.init(ngModelCtrl, uibPagerConfig);
38105             }
38106           };
38107         }]);
38108
38109         angular.module('ui.bootstrap.pagination', ['ui.bootstrap.paging'])
38110         .controller('UibPaginationController', ['$scope', '$attrs', '$parse', 'uibPaging', 'uibPaginationConfig', function($scope, $attrs, $parse, uibPaging, uibPaginationConfig) {
38111           var ctrl = this;
38112           // Setup configuration parameters
38113           var maxSize = angular.isDefined($attrs.maxSize) ? $scope.$parent.$eval($attrs.maxSize) : uibPaginationConfig.maxSize,
38114             rotate = angular.isDefined($attrs.rotate) ? $scope.$parent.$eval($attrs.rotate) : uibPaginationConfig.rotate,
38115             forceEllipses = angular.isDefined($attrs.forceEllipses) ? $scope.$parent.$eval($attrs.forceEllipses) : uibPaginationConfig.forceEllipses,
38116             boundaryLinkNumbers = angular.isDefined($attrs.boundaryLinkNumbers) ? $scope.$parent.$eval($attrs.boundaryLinkNumbers) : uibPaginationConfig.boundaryLinkNumbers;
38117           $scope.boundaryLinks = angular.isDefined($attrs.boundaryLinks) ? $scope.$parent.$eval($attrs.boundaryLinks) : uibPaginationConfig.boundaryLinks;
38118           $scope.directionLinks = angular.isDefined($attrs.directionLinks) ? $scope.$parent.$eval($attrs.directionLinks) : uibPaginationConfig.directionLinks;
38119
38120           uibPaging.create(this, $scope, $attrs);
38121
38122           if ($attrs.maxSize) {
38123             $scope.$parent.$watch($parse($attrs.maxSize), function(value) {
38124               maxSize = parseInt(value, 10);
38125               ctrl.render();
38126             });
38127           }
38128
38129           // Create page object used in template
38130           function makePage(number, text, isActive) {
38131             return {
38132               number: number,
38133               text: text,
38134               active: isActive
38135             };
38136           }
38137
38138           function getPages(currentPage, totalPages) {
38139             var pages = [];
38140
38141             // Default page limits
38142             var startPage = 1, endPage = totalPages;
38143             var isMaxSized = angular.isDefined(maxSize) && maxSize < totalPages;
38144
38145             // recompute if maxSize
38146             if (isMaxSized) {
38147               if (rotate) {
38148                 // Current page is displayed in the middle of the visible ones
38149                 startPage = Math.max(currentPage - Math.floor(maxSize / 2), 1);
38150                 endPage = startPage + maxSize - 1;
38151
38152                 // Adjust if limit is exceeded
38153                 if (endPage > totalPages) {
38154                   endPage = totalPages;
38155                   startPage = endPage - maxSize + 1;
38156                 }
38157               } else {
38158                 // Visible pages are paginated with maxSize
38159                 startPage = (Math.ceil(currentPage / maxSize) - 1) * maxSize + 1;
38160
38161                 // Adjust last page if limit is exceeded
38162                 endPage = Math.min(startPage + maxSize - 1, totalPages);
38163               }
38164             }
38165
38166             // Add page number links
38167             for (var number = startPage; number <= endPage; number++) {
38168               var page = makePage(number, number, number === currentPage);
38169               pages.push(page);
38170             }
38171
38172             // Add links to move between page sets
38173             if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) {
38174               if (startPage > 1) {
38175                 if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning
38176                 var previousPageSet = makePage(startPage - 1, '...', false);
38177                 pages.unshift(previousPageSet);
38178               }
38179                 if (boundaryLinkNumbers) {
38180                   if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential
38181                     var secondPageLink = makePage(2, '2', false);
38182                     pages.unshift(secondPageLink);
38183                   }
38184                   //add the first page
38185                   var firstPageLink = makePage(1, '1', false);
38186                   pages.unshift(firstPageLink);
38187                 }
38188               }
38189
38190               if (endPage < totalPages) {
38191                 if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end
38192                 var nextPageSet = makePage(endPage + 1, '...', false);
38193                 pages.push(nextPageSet);
38194               }
38195                 if (boundaryLinkNumbers) {
38196                   if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential
38197                     var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false);
38198                     pages.push(secondToLastPageLink);
38199                   }
38200                   //add the last page
38201                   var lastPageLink = makePage(totalPages, totalPages, false);
38202                   pages.push(lastPageLink);
38203                 }
38204               }
38205             }
38206             return pages;
38207           }
38208
38209           var originalRender = this.render;
38210           this.render = function() {
38211             originalRender();
38212             if ($scope.page > 0 && $scope.page <= $scope.totalPages) {
38213               $scope.pages = getPages($scope.page, $scope.totalPages);
38214             }
38215           };
38216         }])
38217
38218         .constant('uibPaginationConfig', {
38219           itemsPerPage: 10,
38220           boundaryLinks: false,
38221           boundaryLinkNumbers: false,
38222           directionLinks: true,
38223           firstText: 'First',
38224           previousText: 'Previous',
38225           nextText: 'Next',
38226           lastText: 'Last',
38227           rotate: true,
38228           forceEllipses: false
38229         })
38230
38231         .directive('uibPagination', ['$parse', 'uibPaginationConfig', function($parse, uibPaginationConfig) {
38232           return {
38233             scope: {
38234               totalItems: '=',
38235               firstText: '@',
38236               previousText: '@',
38237               nextText: '@',
38238               lastText: '@',
38239               ngDisabled:'='
38240             },
38241             require: ['uibPagination', '?ngModel'],
38242             controller: 'UibPaginationController',
38243             controllerAs: 'pagination',
38244             templateUrl: function(element, attrs) {
38245               return attrs.templateUrl || 'uib/template/pagination/pagination.html';
38246             },
38247             replace: true,
38248             link: function(scope, element, attrs, ctrls) {
38249               var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
38250
38251               if (!ngModelCtrl) {
38252                  return; // do nothing if no ng-model
38253               }
38254
38255               paginationCtrl.init(ngModelCtrl, uibPaginationConfig);
38256             }
38257           };
38258         }]);
38259
38260         /**
38261          * The following features are still outstanding: animation as a
38262          * function, placement as a function, inside, support for more triggers than
38263          * just mouse enter/leave, html tooltips, and selector delegation.
38264          */
38265         angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.stackedMap'])
38266
38267         /**
38268          * The $tooltip service creates tooltip- and popover-like directives as well as
38269          * houses global options for them.
38270          */
38271         .provider('$uibTooltip', function() {
38272           // The default options tooltip and popover.
38273           var defaultOptions = {
38274             placement: 'top',
38275             placementClassPrefix: '',
38276             animation: true,
38277             popupDelay: 0,
38278             popupCloseDelay: 0,
38279             useContentExp: false
38280           };
38281
38282           // Default hide triggers for each show trigger
38283           var triggerMap = {
38284             'mouseenter': 'mouseleave',
38285             'click': 'click',
38286             'outsideClick': 'outsideClick',
38287             'focus': 'blur',
38288             'none': ''
38289           };
38290
38291           // The options specified to the provider globally.
38292           var globalOptions = {};
38293
38294           /**
38295            * `options({})` allows global configuration of all tooltips in the
38296            * application.
38297            *
38298            *   var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
38299            *     // place tooltips left instead of top by default
38300            *     $tooltipProvider.options( { placement: 'left' } );
38301            *   });
38302            */
38303                 this.options = function(value) {
38304                         angular.extend(globalOptions, value);
38305                 };
38306
38307           /**
38308            * This allows you to extend the set of trigger mappings available. E.g.:
38309            *
38310            *   $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
38311            */
38312           this.setTriggers = function setTriggers(triggers) {
38313             angular.extend(triggerMap, triggers);
38314           };
38315
38316           /**
38317            * This is a helper function for translating camel-case to snake_case.
38318            */
38319           function snake_case(name) {
38320             var regexp = /[A-Z]/g;
38321             var separator = '-';
38322             return name.replace(regexp, function(letter, pos) {
38323               return (pos ? separator : '') + letter.toLowerCase();
38324             });
38325           }
38326
38327           /**
38328            * Returns the actual instance of the $tooltip service.
38329            * TODO support multiple triggers
38330            */
38331           this.$get = ['$window', '$compile', '$timeout', '$document', '$uibPosition', '$interpolate', '$rootScope', '$parse', '$$stackedMap', function($window, $compile, $timeout, $document, $position, $interpolate, $rootScope, $parse, $$stackedMap) {
38332             var openedTooltips = $$stackedMap.createNew();
38333             $document.on('keypress', keypressListener);
38334
38335             $rootScope.$on('$destroy', function() {
38336               $document.off('keypress', keypressListener);
38337             });
38338
38339             function keypressListener(e) {
38340               if (e.which === 27) {
38341                 var last = openedTooltips.top();
38342                 if (last) {
38343                   last.value.close();
38344                   openedTooltips.removeTop();
38345                   last = null;
38346                 }
38347               }
38348             }
38349
38350             return function $tooltip(ttType, prefix, defaultTriggerShow, options) {
38351               options = angular.extend({}, defaultOptions, globalOptions, options);
38352
38353               /**
38354                * Returns an object of show and hide triggers.
38355                *
38356                * If a trigger is supplied,
38357                * it is used to show the tooltip; otherwise, it will use the `trigger`
38358                * option passed to the `$tooltipProvider.options` method; else it will
38359                * default to the trigger supplied to this directive factory.
38360                *
38361                * The hide trigger is based on the show trigger. If the `trigger` option
38362                * was passed to the `$tooltipProvider.options` method, it will use the
38363                * mapped trigger from `triggerMap` or the passed trigger if the map is
38364                * undefined; otherwise, it uses the `triggerMap` value of the show
38365                * trigger; else it will just use the show trigger.
38366                */
38367               function getTriggers(trigger) {
38368                 var show = (trigger || options.trigger || defaultTriggerShow).split(' ');
38369                 var hide = show.map(function(trigger) {
38370                   return triggerMap[trigger] || trigger;
38371                 });
38372                 return {
38373                   show: show,
38374                   hide: hide
38375                 };
38376               }
38377
38378               var directiveName = snake_case(ttType);
38379
38380               var startSym = $interpolate.startSymbol();
38381               var endSym = $interpolate.endSymbol();
38382               var template =
38383                 '<div '+ directiveName + '-popup '+
38384                   'title="' + startSym + 'title' + endSym + '" '+
38385                   (options.useContentExp ?
38386                     'content-exp="contentExp()" ' :
38387                     'content="' + startSym + 'content' + endSym + '" ') +
38388                   'placement="' + startSym + 'placement' + endSym + '" '+
38389                   'popup-class="' + startSym + 'popupClass' + endSym + '" '+
38390                   'animation="animation" ' +
38391                   'is-open="isOpen"' +
38392                   'origin-scope="origScope" ' +
38393                   'style="visibility: hidden; display: block; top: -9999px; left: -9999px;"' +
38394                   '>' +
38395                 '</div>';
38396
38397               return {
38398                 compile: function(tElem, tAttrs) {
38399                   var tooltipLinker = $compile(template);
38400
38401                   return function link(scope, element, attrs, tooltipCtrl) {
38402                     var tooltip;
38403                     var tooltipLinkedScope;
38404                     var transitionTimeout;
38405                     var showTimeout;
38406                     var hideTimeout;
38407                     var positionTimeout;
38408                     var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
38409                     var triggers = getTriggers(undefined);
38410                     var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
38411                     var ttScope = scope.$new(true);
38412                     var repositionScheduled = false;
38413                     var isOpenParse = angular.isDefined(attrs[prefix + 'IsOpen']) ? $parse(attrs[prefix + 'IsOpen']) : false;
38414                     var contentParse = options.useContentExp ? $parse(attrs[ttType]) : false;
38415                     var observers = [];
38416
38417                     var positionTooltip = function() {
38418                       // check if tooltip exists and is not empty
38419                       if (!tooltip || !tooltip.html()) { return; }
38420
38421                       if (!positionTimeout) {
38422                         positionTimeout = $timeout(function() {
38423                           // Reset the positioning.
38424                           tooltip.css({ top: 0, left: 0 });
38425
38426                           // Now set the calculated positioning.
38427                           var ttPosition = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
38428                           tooltip.css({ top: ttPosition.top + 'px', left: ttPosition.left + 'px', visibility: 'visible' });
38429
38430                           // If the placement class is prefixed, still need
38431                           // to remove the TWBS standard class.
38432                           if (options.placementClassPrefix) {
38433                             tooltip.removeClass('top bottom left right');
38434                           }
38435
38436                           tooltip.removeClass(
38437                             options.placementClassPrefix + 'top ' +
38438                             options.placementClassPrefix + 'top-left ' +
38439                             options.placementClassPrefix + 'top-right ' +
38440                             options.placementClassPrefix + 'bottom ' +
38441                             options.placementClassPrefix + 'bottom-left ' +
38442                             options.placementClassPrefix + 'bottom-right ' +
38443                             options.placementClassPrefix + 'left ' +
38444                             options.placementClassPrefix + 'left-top ' +
38445                             options.placementClassPrefix + 'left-bottom ' +
38446                             options.placementClassPrefix + 'right ' +
38447                             options.placementClassPrefix + 'right-top ' +
38448                             options.placementClassPrefix + 'right-bottom');
38449
38450                           var placement = ttPosition.placement.split('-');
38451                           tooltip.addClass(placement[0], options.placementClassPrefix + ttPosition.placement);
38452                           $position.positionArrow(tooltip, ttPosition.placement);
38453
38454                           positionTimeout = null;
38455                         }, 0, false);
38456                       }
38457                     };
38458
38459                     // Set up the correct scope to allow transclusion later
38460                     ttScope.origScope = scope;
38461
38462                     // By default, the tooltip is not open.
38463                     // TODO add ability to start tooltip opened
38464                     ttScope.isOpen = false;
38465                     openedTooltips.add(ttScope, {
38466                       close: hide
38467                     });
38468
38469                     function toggleTooltipBind() {
38470                       if (!ttScope.isOpen) {
38471                         showTooltipBind();
38472                       } else {
38473                         hideTooltipBind();
38474                       }
38475                     }
38476
38477                     // Show the tooltip with delay if specified, otherwise show it immediately
38478                     function showTooltipBind() {
38479                       if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
38480                         return;
38481                       }
38482
38483                       cancelHide();
38484                       prepareTooltip();
38485
38486                       if (ttScope.popupDelay) {
38487                         // Do nothing if the tooltip was already scheduled to pop-up.
38488                         // This happens if show is triggered multiple times before any hide is triggered.
38489                         if (!showTimeout) {
38490                           showTimeout = $timeout(show, ttScope.popupDelay, false);
38491                         }
38492                       } else {
38493                         show();
38494                       }
38495                     }
38496
38497                     function hideTooltipBind() {
38498                       cancelShow();
38499
38500                       if (ttScope.popupCloseDelay) {
38501                         if (!hideTimeout) {
38502                           hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
38503                         }
38504                       } else {
38505                         hide();
38506                       }
38507                     }
38508
38509                     // Show the tooltip popup element.
38510                     function show() {
38511                       cancelShow();
38512                       cancelHide();
38513
38514                       // Don't show empty tooltips.
38515                       if (!ttScope.content) {
38516                         return angular.noop;
38517                       }
38518
38519                       createTooltip();
38520
38521                       // And show the tooltip.
38522                       ttScope.$evalAsync(function() {
38523                         ttScope.isOpen = true;
38524                         assignIsOpen(true);
38525                         positionTooltip();
38526                       });
38527                     }
38528
38529                     function cancelShow() {
38530                       if (showTimeout) {
38531                         $timeout.cancel(showTimeout);
38532                         showTimeout = null;
38533                       }
38534
38535                       if (positionTimeout) {
38536                         $timeout.cancel(positionTimeout);
38537                         positionTimeout = null;
38538                       }
38539                     }
38540
38541                     // Hide the tooltip popup element.
38542                     function hide() {
38543                       if (!ttScope) {
38544                         return;
38545                       }
38546
38547                       // First things first: we don't show it anymore.
38548                       ttScope.$evalAsync(function() {
38549                         ttScope.isOpen = false;
38550                         assignIsOpen(false);
38551                         // And now we remove it from the DOM. However, if we have animation, we
38552                         // need to wait for it to expire beforehand.
38553                         // FIXME: this is a placeholder for a port of the transitions library.
38554                         // The fade transition in TWBS is 150ms.
38555                         if (ttScope.animation) {
38556                           if (!transitionTimeout) {
38557                             transitionTimeout = $timeout(removeTooltip, 150, false);
38558                           }
38559                         } else {
38560                           removeTooltip();
38561                         }
38562                       });
38563                     }
38564
38565                     function cancelHide() {
38566                       if (hideTimeout) {
38567                         $timeout.cancel(hideTimeout);
38568                         hideTimeout = null;
38569                       }
38570                       if (transitionTimeout) {
38571                         $timeout.cancel(transitionTimeout);
38572                         transitionTimeout = null;
38573                       }
38574                     }
38575
38576                     function createTooltip() {
38577                       // There can only be one tooltip element per directive shown at once.
38578                       if (tooltip) {
38579                         return;
38580                       }
38581
38582                       tooltipLinkedScope = ttScope.$new();
38583                       tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) {
38584                         if (appendToBody) {
38585                           $document.find('body').append(tooltip);
38586                         } else {
38587                           element.after(tooltip);
38588                         }
38589                       });
38590
38591                       prepObservers();
38592                     }
38593
38594                     function removeTooltip() {
38595                       cancelShow();
38596                       cancelHide();
38597                       unregisterObservers();
38598
38599                       if (tooltip) {
38600                         tooltip.remove();
38601                         tooltip = null;
38602                       }
38603                       if (tooltipLinkedScope) {
38604                         tooltipLinkedScope.$destroy();
38605                         tooltipLinkedScope = null;
38606                       }
38607                     }
38608
38609                     /**
38610                      * Set the initial scope values. Once
38611                      * the tooltip is created, the observers
38612                      * will be added to keep things in sync.
38613                      */
38614                     function prepareTooltip() {
38615                       ttScope.title = attrs[prefix + 'Title'];
38616                       if (contentParse) {
38617                         ttScope.content = contentParse(scope);
38618                       } else {
38619                         ttScope.content = attrs[ttType];
38620                       }
38621
38622                       ttScope.popupClass = attrs[prefix + 'Class'];
38623                       ttScope.placement = angular.isDefined(attrs[prefix + 'Placement']) ? attrs[prefix + 'Placement'] : options.placement;
38624
38625                       var delay = parseInt(attrs[prefix + 'PopupDelay'], 10);
38626                       var closeDelay = parseInt(attrs[prefix + 'PopupCloseDelay'], 10);
38627                       ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay;
38628                       ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay;
38629                     }
38630
38631                     function assignIsOpen(isOpen) {
38632                       if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
38633                         isOpenParse.assign(scope, isOpen);
38634                       }
38635                     }
38636
38637                     ttScope.contentExp = function() {
38638                       return ttScope.content;
38639                     };
38640
38641                     /**
38642                      * Observe the relevant attributes.
38643                      */
38644                     attrs.$observe('disabled', function(val) {
38645                       if (val) {
38646                         cancelShow();
38647                       }
38648
38649                       if (val && ttScope.isOpen) {
38650                         hide();
38651                       }
38652                     });
38653
38654                     if (isOpenParse) {
38655                       scope.$watch(isOpenParse, function(val) {
38656                         if (ttScope && !val === ttScope.isOpen) {
38657                           toggleTooltipBind();
38658                         }
38659                       });
38660                     }
38661
38662                     function prepObservers() {
38663                       observers.length = 0;
38664
38665                       if (contentParse) {
38666                         observers.push(
38667                           scope.$watch(contentParse, function(val) {
38668                             ttScope.content = val;
38669                             if (!val && ttScope.isOpen) {
38670                               hide();
38671                             }
38672                           })
38673                         );
38674
38675                         observers.push(
38676                           tooltipLinkedScope.$watch(function() {
38677                             if (!repositionScheduled) {
38678                               repositionScheduled = true;
38679                               tooltipLinkedScope.$$postDigest(function() {
38680                                 repositionScheduled = false;
38681                                 if (ttScope && ttScope.isOpen) {
38682                                   positionTooltip();
38683                                 }
38684                               });
38685                             }
38686                           })
38687                         );
38688                       } else {
38689                         observers.push(
38690                           attrs.$observe(ttType, function(val) {
38691                             ttScope.content = val;
38692                             if (!val && ttScope.isOpen) {
38693                               hide();
38694                             } else {
38695                               positionTooltip();
38696                             }
38697                           })
38698                         );
38699                       }
38700
38701                       observers.push(
38702                         attrs.$observe(prefix + 'Title', function(val) {
38703                           ttScope.title = val;
38704                           if (ttScope.isOpen) {
38705                             positionTooltip();
38706                           }
38707                         })
38708                       );
38709
38710                       observers.push(
38711                         attrs.$observe(prefix + 'Placement', function(val) {
38712                           ttScope.placement = val ? val : options.placement;
38713                           if (ttScope.isOpen) {
38714                             positionTooltip();
38715                           }
38716                         })
38717                       );
38718                     }
38719
38720                     function unregisterObservers() {
38721                       if (observers.length) {
38722                         angular.forEach(observers, function(observer) {
38723                           observer();
38724                         });
38725                         observers.length = 0;
38726                       }
38727                     }
38728
38729                     // hide tooltips/popovers for outsideClick trigger
38730                     function bodyHideTooltipBind(e) {
38731                       if (!ttScope || !ttScope.isOpen || !tooltip) {
38732                         return;
38733                       }
38734                       // make sure the tooltip/popover link or tool tooltip/popover itself were not clicked
38735                       if (!element[0].contains(e.target) && !tooltip[0].contains(e.target)) {
38736                         hideTooltipBind();
38737                       }
38738                     }
38739
38740                     var unregisterTriggers = function() {
38741                       triggers.show.forEach(function(trigger) {
38742                         if (trigger === 'outsideClick') {
38743                           element.off('click', toggleTooltipBind);
38744                         } else {
38745                           element.off(trigger, showTooltipBind);
38746                           element.off(trigger, toggleTooltipBind);
38747                         }
38748                       });
38749                       triggers.hide.forEach(function(trigger) {
38750                         if (trigger === 'outsideClick') {
38751                           $document.off('click', bodyHideTooltipBind);
38752                         } else {
38753                           element.off(trigger, hideTooltipBind);
38754                         }
38755                       });
38756                     };
38757
38758                     function prepTriggers() {
38759                       var val = attrs[prefix + 'Trigger'];
38760                       unregisterTriggers();
38761
38762                       triggers = getTriggers(val);
38763
38764                       if (triggers.show !== 'none') {
38765                         triggers.show.forEach(function(trigger, idx) {
38766                           if (trigger === 'outsideClick') {
38767                             element.on('click', toggleTooltipBind);
38768                             $document.on('click', bodyHideTooltipBind);
38769                           } else if (trigger === triggers.hide[idx]) {
38770                             element.on(trigger, toggleTooltipBind);
38771                           } else if (trigger) {
38772                             element.on(trigger, showTooltipBind);
38773                             element.on(triggers.hide[idx], hideTooltipBind);
38774                           }
38775
38776                           element.on('keypress', function(e) {
38777                             if (e.which === 27) {
38778                               hideTooltipBind();
38779                             }
38780                           });
38781                         });
38782                       }
38783                     }
38784
38785                     prepTriggers();
38786
38787                     var animation = scope.$eval(attrs[prefix + 'Animation']);
38788                     ttScope.animation = angular.isDefined(animation) ? !!animation : options.animation;
38789
38790                     var appendToBodyVal;
38791                     var appendKey = prefix + 'AppendToBody';
38792                     if (appendKey in attrs && attrs[appendKey] === undefined) {
38793                       appendToBodyVal = true;
38794                     } else {
38795                       appendToBodyVal = scope.$eval(attrs[appendKey]);
38796                     }
38797
38798                     appendToBody = angular.isDefined(appendToBodyVal) ? appendToBodyVal : appendToBody;
38799
38800                     // if a tooltip is attached to <body> we need to remove it on
38801                     // location change as its parent scope will probably not be destroyed
38802                     // by the change.
38803                     if (appendToBody) {
38804                       scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess() {
38805                         if (ttScope.isOpen) {
38806                           hide();
38807                         }
38808                       });
38809                     }
38810
38811                     // Make sure tooltip is destroyed and removed.
38812                     scope.$on('$destroy', function onDestroyTooltip() {
38813                       unregisterTriggers();
38814                       removeTooltip();
38815                       openedTooltips.remove(ttScope);
38816                       ttScope = null;
38817                     });
38818                   };
38819                 }
38820               };
38821             };
38822           }];
38823         })
38824
38825         // This is mostly ngInclude code but with a custom scope
38826         .directive('uibTooltipTemplateTransclude', [
38827                  '$animate', '$sce', '$compile', '$templateRequest',
38828         function ($animate, $sce, $compile, $templateRequest) {
38829           return {
38830             link: function(scope, elem, attrs) {
38831               var origScope = scope.$eval(attrs.tooltipTemplateTranscludeScope);
38832
38833               var changeCounter = 0,
38834                 currentScope,
38835                 previousElement,
38836                 currentElement;
38837
38838               var cleanupLastIncludeContent = function() {
38839                 if (previousElement) {
38840                   previousElement.remove();
38841                   previousElement = null;
38842                 }
38843
38844                 if (currentScope) {
38845                   currentScope.$destroy();
38846                   currentScope = null;
38847                 }
38848
38849                 if (currentElement) {
38850                   $animate.leave(currentElement).then(function() {
38851                     previousElement = null;
38852                   });
38853                   previousElement = currentElement;
38854                   currentElement = null;
38855                 }
38856               };
38857
38858               scope.$watch($sce.parseAsResourceUrl(attrs.uibTooltipTemplateTransclude), function(src) {
38859                 var thisChangeId = ++changeCounter;
38860
38861                 if (src) {
38862                   //set the 2nd param to true to ignore the template request error so that the inner
38863                   //contents and scope can be cleaned up.
38864                   $templateRequest(src, true).then(function(response) {
38865                     if (thisChangeId !== changeCounter) { return; }
38866                     var newScope = origScope.$new();
38867                     var template = response;
38868
38869                     var clone = $compile(template)(newScope, function(clone) {
38870                       cleanupLastIncludeContent();
38871                       $animate.enter(clone, elem);
38872                     });
38873
38874                     currentScope = newScope;
38875                     currentElement = clone;
38876
38877                     currentScope.$emit('$includeContentLoaded', src);
38878                   }, function() {
38879                     if (thisChangeId === changeCounter) {
38880                       cleanupLastIncludeContent();
38881                       scope.$emit('$includeContentError', src);
38882                     }
38883                   });
38884                   scope.$emit('$includeContentRequested', src);
38885                 } else {
38886                   cleanupLastIncludeContent();
38887                 }
38888               });
38889
38890               scope.$on('$destroy', cleanupLastIncludeContent);
38891             }
38892           };
38893         }])
38894
38895         /**
38896          * Note that it's intentional that these classes are *not* applied through $animate.
38897          * They must not be animated as they're expected to be present on the tooltip on
38898          * initialization.
38899          */
38900         .directive('uibTooltipClasses', ['$uibPosition', function($uibPosition) {
38901           return {
38902             restrict: 'A',
38903             link: function(scope, element, attrs) {
38904               // need to set the primary position so the
38905               // arrow has space during position measure.
38906               // tooltip.positionTooltip()
38907               if (scope.placement) {
38908                 // // There are no top-left etc... classes
38909                 // // in TWBS, so we need the primary position.
38910                 var position = $uibPosition.parsePlacement(scope.placement);
38911                 element.addClass(position[0]);
38912               } else {
38913                 element.addClass('top');
38914               }
38915
38916               if (scope.popupClass) {
38917                 element.addClass(scope.popupClass);
38918               }
38919
38920               if (scope.animation()) {
38921                 element.addClass(attrs.tooltipAnimationClass);
38922               }
38923             }
38924           };
38925         }])
38926
38927         .directive('uibTooltipPopup', function() {
38928           return {
38929             replace: true,
38930             scope: { content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
38931             templateUrl: 'uib/template/tooltip/tooltip-popup.html'
38932           };
38933         })
38934
38935         .directive('uibTooltip', [ '$uibTooltip', function($uibTooltip) {
38936           return $uibTooltip('uibTooltip', 'tooltip', 'mouseenter');
38937         }])
38938
38939         .directive('uibTooltipTemplatePopup', function() {
38940           return {
38941             replace: true,
38942             scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&',
38943               originScope: '&' },
38944             templateUrl: 'uib/template/tooltip/tooltip-template-popup.html'
38945           };
38946         })
38947
38948         .directive('uibTooltipTemplate', ['$uibTooltip', function($uibTooltip) {
38949           return $uibTooltip('uibTooltipTemplate', 'tooltip', 'mouseenter', {
38950             useContentExp: true
38951           });
38952         }])
38953
38954         .directive('uibTooltipHtmlPopup', function() {
38955           return {
38956             replace: true,
38957             scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
38958             templateUrl: 'uib/template/tooltip/tooltip-html-popup.html'
38959           };
38960         })
38961
38962         .directive('uibTooltipHtml', ['$uibTooltip', function($uibTooltip) {
38963           return $uibTooltip('uibTooltipHtml', 'tooltip', 'mouseenter', {
38964             useContentExp: true
38965           });
38966         }]);
38967
38968         /**
38969          * The following features are still outstanding: popup delay, animation as a
38970          * function, placement as a function, inside, support for more triggers than
38971          * just mouse enter/leave, and selector delegatation.
38972          */
38973         angular.module('ui.bootstrap.popover', ['ui.bootstrap.tooltip'])
38974
38975         .directive('uibPopoverTemplatePopup', function() {
38976           return {
38977             replace: true,
38978             scope: { title: '@', contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&',
38979               originScope: '&' },
38980             templateUrl: 'uib/template/popover/popover-template.html'
38981           };
38982         })
38983
38984         .directive('uibPopoverTemplate', ['$uibTooltip', function($uibTooltip) {
38985           return $uibTooltip('uibPopoverTemplate', 'popover', 'click', {
38986             useContentExp: true
38987           });
38988         }])
38989
38990         .directive('uibPopoverHtmlPopup', function() {
38991           return {
38992             replace: true,
38993             scope: { contentExp: '&', title: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
38994             templateUrl: 'uib/template/popover/popover-html.html'
38995           };
38996         })
38997
38998         .directive('uibPopoverHtml', ['$uibTooltip', function($uibTooltip) {
38999           return $uibTooltip('uibPopoverHtml', 'popover', 'click', {
39000             useContentExp: true
39001           });
39002         }])
39003
39004         .directive('uibPopoverPopup', function() {
39005           return {
39006             replace: true,
39007             scope: { title: '@', content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
39008             templateUrl: 'uib/template/popover/popover.html'
39009           };
39010         })
39011
39012         .directive('uibPopover', ['$uibTooltip', function($uibTooltip) {
39013           return $uibTooltip('uibPopover', 'popover', 'click');
39014         }]);
39015
39016         angular.module('ui.bootstrap.progressbar', [])
39017
39018         .constant('uibProgressConfig', {
39019           animate: true,
39020           max: 100
39021         })
39022
39023         .controller('UibProgressController', ['$scope', '$attrs', 'uibProgressConfig', function($scope, $attrs, progressConfig) {
39024           var self = this,
39025               animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
39026
39027           this.bars = [];
39028           $scope.max = angular.isDefined($scope.max) ? $scope.max : progressConfig.max;
39029
39030           this.addBar = function(bar, element, attrs) {
39031             if (!animate) {
39032               element.css({'transition': 'none'});
39033             }
39034
39035             this.bars.push(bar);
39036
39037             bar.max = $scope.max;
39038             bar.title = attrs && angular.isDefined(attrs.title) ? attrs.title : 'progressbar';
39039
39040             bar.$watch('value', function(value) {
39041               bar.recalculatePercentage();
39042             });
39043
39044             bar.recalculatePercentage = function() {
39045               var totalPercentage = self.bars.reduce(function(total, bar) {
39046                 bar.percent = +(100 * bar.value / bar.max).toFixed(2);
39047                 return total + bar.percent;
39048               }, 0);
39049
39050               if (totalPercentage > 100) {
39051                 bar.percent -= totalPercentage - 100;
39052               }
39053             };
39054
39055             bar.$on('$destroy', function() {
39056               element = null;
39057               self.removeBar(bar);
39058             });
39059           };
39060
39061           this.removeBar = function(bar) {
39062             this.bars.splice(this.bars.indexOf(bar), 1);
39063             this.bars.forEach(function (bar) {
39064               bar.recalculatePercentage();
39065             });
39066           };
39067
39068           $scope.$watch('max', function(max) {
39069             self.bars.forEach(function(bar) {
39070               bar.max = $scope.max;
39071               bar.recalculatePercentage();
39072             });
39073           });
39074         }])
39075
39076         .directive('uibProgress', function() {
39077           return {
39078             replace: true,
39079             transclude: true,
39080             controller: 'UibProgressController',
39081             require: 'uibProgress',
39082             scope: {
39083               max: '=?'
39084             },
39085             templateUrl: 'uib/template/progressbar/progress.html'
39086           };
39087         })
39088
39089         .directive('uibBar', function() {
39090           return {
39091             replace: true,
39092             transclude: true,
39093             require: '^uibProgress',
39094             scope: {
39095               value: '=',
39096               type: '@'
39097             },
39098             templateUrl: 'uib/template/progressbar/bar.html',
39099             link: function(scope, element, attrs, progressCtrl) {
39100               progressCtrl.addBar(scope, element, attrs);
39101             }
39102           };
39103         })
39104
39105         .directive('uibProgressbar', function() {
39106           return {
39107             replace: true,
39108             transclude: true,
39109             controller: 'UibProgressController',
39110             scope: {
39111               value: '=',
39112               max: '=?',
39113               type: '@'
39114             },
39115             templateUrl: 'uib/template/progressbar/progressbar.html',
39116             link: function(scope, element, attrs, progressCtrl) {
39117               progressCtrl.addBar(scope, angular.element(element.children()[0]), {title: attrs.title});
39118             }
39119           };
39120         });
39121
39122         angular.module('ui.bootstrap.rating', [])
39123
39124         .constant('uibRatingConfig', {
39125           max: 5,
39126           stateOn: null,
39127           stateOff: null,
39128           titles : ['one', 'two', 'three', 'four', 'five']
39129         })
39130
39131         .controller('UibRatingController', ['$scope', '$attrs', 'uibRatingConfig', function($scope, $attrs, ratingConfig) {
39132           var ngModelCtrl = { $setViewValue: angular.noop };
39133
39134           this.init = function(ngModelCtrl_) {
39135             ngModelCtrl = ngModelCtrl_;
39136             ngModelCtrl.$render = this.render;
39137
39138             ngModelCtrl.$formatters.push(function(value) {
39139               if (angular.isNumber(value) && value << 0 !== value) {
39140                 value = Math.round(value);
39141               }
39142
39143               return value;
39144             });
39145
39146             this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
39147             this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
39148             var tmpTitles = angular.isDefined($attrs.titles) ? $scope.$parent.$eval($attrs.titles) : ratingConfig.titles ;
39149             this.titles = angular.isArray(tmpTitles) && tmpTitles.length > 0 ?
39150               tmpTitles : ratingConfig.titles;
39151
39152             var ratingStates = angular.isDefined($attrs.ratingStates) ?
39153               $scope.$parent.$eval($attrs.ratingStates) :
39154               new Array(angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max);
39155             $scope.range = this.buildTemplateObjects(ratingStates);
39156           };
39157
39158           this.buildTemplateObjects = function(states) {
39159             for (var i = 0, n = states.length; i < n; i++) {
39160               states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff, title: this.getTitle(i) }, states[i]);
39161             }
39162             return states;
39163           };
39164
39165           this.getTitle = function(index) {
39166             if (index >= this.titles.length) {
39167               return index + 1;
39168             }
39169
39170             return this.titles[index];
39171           };
39172
39173           $scope.rate = function(value) {
39174             if (!$scope.readonly && value >= 0 && value <= $scope.range.length) {
39175               ngModelCtrl.$setViewValue(ngModelCtrl.$viewValue === value ? 0 : value);
39176               ngModelCtrl.$render();
39177             }
39178           };
39179
39180           $scope.enter = function(value) {
39181             if (!$scope.readonly) {
39182               $scope.value = value;
39183             }
39184             $scope.onHover({value: value});
39185           };
39186
39187           $scope.reset = function() {
39188             $scope.value = ngModelCtrl.$viewValue;
39189             $scope.onLeave();
39190           };
39191
39192           $scope.onKeydown = function(evt) {
39193             if (/(37|38|39|40)/.test(evt.which)) {
39194               evt.preventDefault();
39195               evt.stopPropagation();
39196               $scope.rate($scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1));
39197             }
39198           };
39199
39200           this.render = function() {
39201             $scope.value = ngModelCtrl.$viewValue;
39202           };
39203         }])
39204
39205         .directive('uibRating', function() {
39206           return {
39207             require: ['uibRating', 'ngModel'],
39208             scope: {
39209               readonly: '=?',
39210               onHover: '&',
39211               onLeave: '&'
39212             },
39213             controller: 'UibRatingController',
39214             templateUrl: 'uib/template/rating/rating.html',
39215             replace: true,
39216             link: function(scope, element, attrs, ctrls) {
39217               var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1];
39218               ratingCtrl.init(ngModelCtrl);
39219             }
39220           };
39221         });
39222
39223         angular.module('ui.bootstrap.tabs', [])
39224
39225         .controller('UibTabsetController', ['$scope', function ($scope) {
39226           var ctrl = this,
39227               tabs = ctrl.tabs = $scope.tabs = [];
39228
39229           ctrl.select = function(selectedTab) {
39230             angular.forEach(tabs, function(tab) {
39231               if (tab.active && tab !== selectedTab) {
39232                 tab.active = false;
39233                 tab.onDeselect();
39234                 selectedTab.selectCalled = false;
39235               }
39236             });
39237             selectedTab.active = true;
39238             // only call select if it has not already been called
39239             if (!selectedTab.selectCalled) {
39240               selectedTab.onSelect();
39241               selectedTab.selectCalled = true;
39242             }
39243           };
39244
39245           ctrl.addTab = function addTab(tab) {
39246             tabs.push(tab);
39247             // we can't run the select function on the first tab
39248             // since that would select it twice
39249             if (tabs.length === 1 && tab.active !== false) {
39250               tab.active = true;
39251             } else if (tab.active) {
39252               ctrl.select(tab);
39253             } else {
39254               tab.active = false;
39255             }
39256           };
39257
39258           ctrl.removeTab = function removeTab(tab) {
39259             var index = tabs.indexOf(tab);
39260             //Select a new tab if the tab to be removed is selected and not destroyed
39261             if (tab.active && tabs.length > 1 && !destroyed) {
39262               //If this is the last tab, select the previous tab. else, the next tab.
39263               var newActiveIndex = index === tabs.length - 1 ? index - 1 : index + 1;
39264               ctrl.select(tabs[newActiveIndex]);
39265             }
39266             tabs.splice(index, 1);
39267           };
39268
39269           var destroyed;
39270           $scope.$on('$destroy', function() {
39271             destroyed = true;
39272           });
39273         }])
39274
39275         .directive('uibTabset', function() {
39276           return {
39277             transclude: true,
39278             replace: true,
39279             scope: {
39280               type: '@'
39281             },
39282             controller: 'UibTabsetController',
39283             templateUrl: 'uib/template/tabs/tabset.html',
39284             link: function(scope, element, attrs) {
39285               scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
39286               scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
39287             }
39288           };
39289         })
39290
39291         .directive('uibTab', ['$parse', function($parse) {
39292           return {
39293             require: '^uibTabset',
39294             replace: true,
39295             templateUrl: 'uib/template/tabs/tab.html',
39296             transclude: true,
39297             scope: {
39298               active: '=?',
39299               heading: '@',
39300               onSelect: '&select', //This callback is called in contentHeadingTransclude
39301                                   //once it inserts the tab's content into the dom
39302               onDeselect: '&deselect'
39303             },
39304             controller: function() {
39305               //Empty controller so other directives can require being 'under' a tab
39306             },
39307             controllerAs: 'tab',
39308             link: function(scope, elm, attrs, tabsetCtrl, transclude) {
39309               scope.$watch('active', function(active) {
39310                 if (active) {
39311                   tabsetCtrl.select(scope);
39312                 }
39313               });
39314
39315               scope.disabled = false;
39316               if (attrs.disable) {
39317                 scope.$parent.$watch($parse(attrs.disable), function(value) {
39318                   scope.disabled = !! value;
39319                 });
39320               }
39321
39322               scope.select = function() {
39323                 if (!scope.disabled) {
39324                   scope.active = true;
39325                 }
39326               };
39327
39328               tabsetCtrl.addTab(scope);
39329               scope.$on('$destroy', function() {
39330                 tabsetCtrl.removeTab(scope);
39331               });
39332
39333               //We need to transclude later, once the content container is ready.
39334               //when this link happens, we're inside a tab heading.
39335               scope.$transcludeFn = transclude;
39336             }
39337           };
39338         }])
39339
39340         .directive('uibTabHeadingTransclude', function() {
39341           return {
39342             restrict: 'A',
39343             require: '^uibTab',
39344             link: function(scope, elm) {
39345               scope.$watch('headingElement', function updateHeadingElement(heading) {
39346                 if (heading) {
39347                   elm.html('');
39348                   elm.append(heading);
39349                 }
39350               });
39351             }
39352           };
39353         })
39354
39355         .directive('uibTabContentTransclude', function() {
39356           return {
39357             restrict: 'A',
39358             require: '^uibTabset',
39359             link: function(scope, elm, attrs) {
39360               var tab = scope.$eval(attrs.uibTabContentTransclude);
39361
39362               //Now our tab is ready to be transcluded: both the tab heading area
39363               //and the tab content area are loaded.  Transclude 'em both.
39364               tab.$transcludeFn(tab.$parent, function(contents) {
39365                 angular.forEach(contents, function(node) {
39366                   if (isTabHeading(node)) {
39367                     //Let tabHeadingTransclude know.
39368                     tab.headingElement = node;
39369                   } else {
39370                     elm.append(node);
39371                   }
39372                 });
39373               });
39374             }
39375           };
39376
39377           function isTabHeading(node) {
39378             return node.tagName && (
39379               node.hasAttribute('uib-tab-heading') ||
39380               node.hasAttribute('data-uib-tab-heading') ||
39381               node.hasAttribute('x-uib-tab-heading') ||
39382               node.tagName.toLowerCase() === 'uib-tab-heading' ||
39383               node.tagName.toLowerCase() === 'data-uib-tab-heading' ||
39384               node.tagName.toLowerCase() === 'x-uib-tab-heading'
39385             );
39386           }
39387         });
39388
39389         angular.module('ui.bootstrap.timepicker', [])
39390
39391         .constant('uibTimepickerConfig', {
39392           hourStep: 1,
39393           minuteStep: 1,
39394           secondStep: 1,
39395           showMeridian: true,
39396           showSeconds: false,
39397           meridians: null,
39398           readonlyInput: false,
39399           mousewheel: true,
39400           arrowkeys: true,
39401           showSpinners: true
39402         })
39403
39404         .controller('UibTimepickerController', ['$scope', '$element', '$attrs', '$parse', '$log', '$locale', 'uibTimepickerConfig', function($scope, $element, $attrs, $parse, $log, $locale, timepickerConfig) {
39405           var selected = new Date(),
39406               ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
39407               meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS;
39408
39409           $scope.tabindex = angular.isDefined($attrs.tabindex) ? $attrs.tabindex : 0;
39410           $element.removeAttr('tabindex');
39411
39412           this.init = function(ngModelCtrl_, inputs) {
39413             ngModelCtrl = ngModelCtrl_;
39414             ngModelCtrl.$render = this.render;
39415
39416             ngModelCtrl.$formatters.unshift(function(modelValue) {
39417               return modelValue ? new Date(modelValue) : null;
39418             });
39419
39420             var hoursInputEl = inputs.eq(0),
39421                 minutesInputEl = inputs.eq(1),
39422                 secondsInputEl = inputs.eq(2);
39423
39424             var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel;
39425
39426             if (mousewheel) {
39427               this.setupMousewheelEvents(hoursInputEl, minutesInputEl, secondsInputEl);
39428             }
39429
39430             var arrowkeys = angular.isDefined($attrs.arrowkeys) ? $scope.$parent.$eval($attrs.arrowkeys) : timepickerConfig.arrowkeys;
39431             if (arrowkeys) {
39432               this.setupArrowkeyEvents(hoursInputEl, minutesInputEl, secondsInputEl);
39433             }
39434
39435             $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput;
39436             this.setupInputEvents(hoursInputEl, minutesInputEl, secondsInputEl);
39437           };
39438
39439           var hourStep = timepickerConfig.hourStep;
39440           if ($attrs.hourStep) {
39441             $scope.$parent.$watch($parse($attrs.hourStep), function(value) {
39442               hourStep = parseInt(value, 10);
39443             });
39444           }
39445
39446           var minuteStep = timepickerConfig.minuteStep;
39447           if ($attrs.minuteStep) {
39448             $scope.$parent.$watch($parse($attrs.minuteStep), function(value) {
39449               minuteStep = parseInt(value, 10);
39450             });
39451           }
39452
39453           var min;
39454           $scope.$parent.$watch($parse($attrs.min), function(value) {
39455             var dt = new Date(value);
39456             min = isNaN(dt) ? undefined : dt;
39457           });
39458
39459           var max;
39460           $scope.$parent.$watch($parse($attrs.max), function(value) {
39461             var dt = new Date(value);
39462             max = isNaN(dt) ? undefined : dt;
39463           });
39464
39465           var disabled = false;
39466           if ($attrs.ngDisabled) {
39467             $scope.$parent.$watch($parse($attrs.ngDisabled), function(value) {
39468               disabled = value;
39469             });
39470           }
39471
39472           $scope.noIncrementHours = function() {
39473             var incrementedSelected = addMinutes(selected, hourStep * 60);
39474             return disabled || incrementedSelected > max ||
39475               incrementedSelected < selected && incrementedSelected < min;
39476           };
39477
39478           $scope.noDecrementHours = function() {
39479             var decrementedSelected = addMinutes(selected, -hourStep * 60);
39480             return disabled || decrementedSelected < min ||
39481               decrementedSelected > selected && decrementedSelected > max;
39482           };
39483
39484           $scope.noIncrementMinutes = function() {
39485             var incrementedSelected = addMinutes(selected, minuteStep);
39486             return disabled || incrementedSelected > max ||
39487               incrementedSelected < selected && incrementedSelected < min;
39488           };
39489
39490           $scope.noDecrementMinutes = function() {
39491             var decrementedSelected = addMinutes(selected, -minuteStep);
39492             return disabled || decrementedSelected < min ||
39493               decrementedSelected > selected && decrementedSelected > max;
39494           };
39495
39496           $scope.noIncrementSeconds = function() {
39497             var incrementedSelected = addSeconds(selected, secondStep);
39498             return disabled || incrementedSelected > max ||
39499               incrementedSelected < selected && incrementedSelected < min;
39500           };
39501
39502           $scope.noDecrementSeconds = function() {
39503             var decrementedSelected = addSeconds(selected, -secondStep);
39504             return disabled || decrementedSelected < min ||
39505               decrementedSelected > selected && decrementedSelected > max;
39506           };
39507
39508           $scope.noToggleMeridian = function() {
39509             if (selected.getHours() < 12) {
39510               return disabled || addMinutes(selected, 12 * 60) > max;
39511             }
39512
39513             return disabled || addMinutes(selected, -12 * 60) < min;
39514           };
39515
39516           var secondStep = timepickerConfig.secondStep;
39517           if ($attrs.secondStep) {
39518             $scope.$parent.$watch($parse($attrs.secondStep), function(value) {
39519               secondStep = parseInt(value, 10);
39520             });
39521           }
39522
39523           $scope.showSeconds = timepickerConfig.showSeconds;
39524           if ($attrs.showSeconds) {
39525             $scope.$parent.$watch($parse($attrs.showSeconds), function(value) {
39526               $scope.showSeconds = !!value;
39527             });
39528           }
39529
39530           // 12H / 24H mode
39531           $scope.showMeridian = timepickerConfig.showMeridian;
39532           if ($attrs.showMeridian) {
39533             $scope.$parent.$watch($parse($attrs.showMeridian), function(value) {
39534               $scope.showMeridian = !!value;
39535
39536               if (ngModelCtrl.$error.time) {
39537                 // Evaluate from template
39538                 var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
39539                 if (angular.isDefined(hours) && angular.isDefined(minutes)) {
39540                   selected.setHours(hours);
39541                   refresh();
39542                 }
39543               } else {
39544                 updateTemplate();
39545               }
39546             });
39547           }
39548
39549           // Get $scope.hours in 24H mode if valid
39550           function getHoursFromTemplate() {
39551             var hours = parseInt($scope.hours, 10);
39552             var valid = $scope.showMeridian ? hours > 0 && hours < 13 :
39553               hours >= 0 && hours < 24;
39554             if (!valid) {
39555               return undefined;
39556             }
39557
39558             if ($scope.showMeridian) {
39559               if (hours === 12) {
39560                 hours = 0;
39561               }
39562               if ($scope.meridian === meridians[1]) {
39563                 hours = hours + 12;
39564               }
39565             }
39566             return hours;
39567           }
39568
39569           function getMinutesFromTemplate() {
39570             var minutes = parseInt($scope.minutes, 10);
39571             return minutes >= 0 && minutes < 60 ? minutes : undefined;
39572           }
39573
39574           function getSecondsFromTemplate() {
39575             var seconds = parseInt($scope.seconds, 10);
39576             return seconds >= 0 && seconds < 60 ? seconds : undefined;
39577           }
39578
39579           function pad(value) {
39580             if (value === null) {
39581               return '';
39582             }
39583
39584             return angular.isDefined(value) && value.toString().length < 2 ?
39585               '0' + value : value.toString();
39586           }
39587
39588           // Respond on mousewheel spin
39589           this.setupMousewheelEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
39590             var isScrollingUp = function(e) {
39591               if (e.originalEvent) {
39592                 e = e.originalEvent;
39593               }
39594               //pick correct delta variable depending on event
39595               var delta = e.wheelDelta ? e.wheelDelta : -e.deltaY;
39596               return e.detail || delta > 0;
39597             };
39598
39599             hoursInputEl.bind('mousewheel wheel', function(e) {
39600               if (!disabled) {
39601                 $scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours());
39602               }
39603               e.preventDefault();
39604             });
39605
39606             minutesInputEl.bind('mousewheel wheel', function(e) {
39607               if (!disabled) {
39608                 $scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes());
39609               }
39610               e.preventDefault();
39611             });
39612
39613              secondsInputEl.bind('mousewheel wheel', function(e) {
39614               if (!disabled) {
39615                 $scope.$apply(isScrollingUp(e) ? $scope.incrementSeconds() : $scope.decrementSeconds());
39616               }
39617               e.preventDefault();
39618             });
39619           };
39620
39621           // Respond on up/down arrowkeys
39622           this.setupArrowkeyEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
39623             hoursInputEl.bind('keydown', function(e) {
39624               if (!disabled) {
39625                 if (e.which === 38) { // up
39626                   e.preventDefault();
39627                   $scope.incrementHours();
39628                   $scope.$apply();
39629                 } else if (e.which === 40) { // down
39630                   e.preventDefault();
39631                   $scope.decrementHours();
39632                   $scope.$apply();
39633                 }
39634               }
39635             });
39636
39637             minutesInputEl.bind('keydown', function(e) {
39638               if (!disabled) {
39639                 if (e.which === 38) { // up
39640                   e.preventDefault();
39641                   $scope.incrementMinutes();
39642                   $scope.$apply();
39643                 } else if (e.which === 40) { // down
39644                   e.preventDefault();
39645                   $scope.decrementMinutes();
39646                   $scope.$apply();
39647                 }
39648               }
39649             });
39650
39651             secondsInputEl.bind('keydown', function(e) {
39652               if (!disabled) {
39653                 if (e.which === 38) { // up
39654                   e.preventDefault();
39655                   $scope.incrementSeconds();
39656                   $scope.$apply();
39657                 } else if (e.which === 40) { // down
39658                   e.preventDefault();
39659                   $scope.decrementSeconds();
39660                   $scope.$apply();
39661                 }
39662               }
39663             });
39664           };
39665
39666           this.setupInputEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
39667             if ($scope.readonlyInput) {
39668               $scope.updateHours = angular.noop;
39669               $scope.updateMinutes = angular.noop;
39670               $scope.updateSeconds = angular.noop;
39671               return;
39672             }
39673
39674             var invalidate = function(invalidHours, invalidMinutes, invalidSeconds) {
39675               ngModelCtrl.$setViewValue(null);
39676               ngModelCtrl.$setValidity('time', false);
39677               if (angular.isDefined(invalidHours)) {
39678                 $scope.invalidHours = invalidHours;
39679               }
39680
39681               if (angular.isDefined(invalidMinutes)) {
39682                 $scope.invalidMinutes = invalidMinutes;
39683               }
39684
39685               if (angular.isDefined(invalidSeconds)) {
39686                 $scope.invalidSeconds = invalidSeconds;
39687               }
39688             };
39689
39690             $scope.updateHours = function() {
39691               var hours = getHoursFromTemplate(),
39692                 minutes = getMinutesFromTemplate();
39693
39694               ngModelCtrl.$setDirty();
39695
39696               if (angular.isDefined(hours) && angular.isDefined(minutes)) {
39697                 selected.setHours(hours);
39698                 selected.setMinutes(minutes);
39699                 if (selected < min || selected > max) {
39700                   invalidate(true);
39701                 } else {
39702                   refresh('h');
39703                 }
39704               } else {
39705                 invalidate(true);
39706               }
39707             };
39708
39709             hoursInputEl.bind('blur', function(e) {
39710               ngModelCtrl.$setTouched();
39711               if ($scope.hours === null || $scope.hours === '') {
39712                 invalidate(true);
39713               } else if (!$scope.invalidHours && $scope.hours < 10) {
39714                 $scope.$apply(function() {
39715                   $scope.hours = pad($scope.hours);
39716                 });
39717               }
39718             });
39719
39720             $scope.updateMinutes = function() {
39721               var minutes = getMinutesFromTemplate(),
39722                 hours = getHoursFromTemplate();
39723
39724               ngModelCtrl.$setDirty();
39725
39726               if (angular.isDefined(minutes) && angular.isDefined(hours)) {
39727                 selected.setHours(hours);
39728                 selected.setMinutes(minutes);
39729                 if (selected < min || selected > max) {
39730                   invalidate(undefined, true);
39731                 } else {
39732                   refresh('m');
39733                 }
39734               } else {
39735                 invalidate(undefined, true);
39736               }
39737             };
39738
39739             minutesInputEl.bind('blur', function(e) {
39740               ngModelCtrl.$setTouched();
39741               if ($scope.minutes === null) {
39742                 invalidate(undefined, true);
39743               } else if (!$scope.invalidMinutes && $scope.minutes < 10) {
39744                 $scope.$apply(function() {
39745                   $scope.minutes = pad($scope.minutes);
39746                 });
39747               }
39748             });
39749
39750             $scope.updateSeconds = function() {
39751               var seconds = getSecondsFromTemplate();
39752
39753               ngModelCtrl.$setDirty();
39754
39755               if (angular.isDefined(seconds)) {
39756                 selected.setSeconds(seconds);
39757                 refresh('s');
39758               } else {
39759                 invalidate(undefined, undefined, true);
39760               }
39761             };
39762
39763             secondsInputEl.bind('blur', function(e) {
39764               if (!$scope.invalidSeconds && $scope.seconds < 10) {
39765                 $scope.$apply( function() {
39766                   $scope.seconds = pad($scope.seconds);
39767                 });
39768               }
39769             });
39770
39771           };
39772
39773           this.render = function() {
39774             var date = ngModelCtrl.$viewValue;
39775
39776             if (isNaN(date)) {
39777               ngModelCtrl.$setValidity('time', false);
39778               $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.');
39779             } else {
39780               if (date) {
39781                 selected = date;
39782               }
39783
39784               if (selected < min || selected > max) {
39785                 ngModelCtrl.$setValidity('time', false);
39786                 $scope.invalidHours = true;
39787                 $scope.invalidMinutes = true;
39788               } else {
39789                 makeValid();
39790               }
39791               updateTemplate();
39792             }
39793           };
39794
39795           // Call internally when we know that model is valid.
39796           function refresh(keyboardChange) {
39797             makeValid();
39798             ngModelCtrl.$setViewValue(new Date(selected));
39799             updateTemplate(keyboardChange);
39800           }
39801
39802           function makeValid() {
39803             ngModelCtrl.$setValidity('time', true);
39804             $scope.invalidHours = false;
39805             $scope.invalidMinutes = false;
39806             $scope.invalidSeconds = false;
39807           }
39808
39809           function updateTemplate(keyboardChange) {
39810             if (!ngModelCtrl.$modelValue) {
39811               $scope.hours = null;
39812               $scope.minutes = null;
39813               $scope.seconds = null;
39814               $scope.meridian = meridians[0];
39815             } else {
39816               var hours = selected.getHours(),
39817                 minutes = selected.getMinutes(),
39818                 seconds = selected.getSeconds();
39819
39820               if ($scope.showMeridian) {
39821                 hours = hours === 0 || hours === 12 ? 12 : hours % 12; // Convert 24 to 12 hour system
39822               }
39823
39824               $scope.hours = keyboardChange === 'h' ? hours : pad(hours);
39825               if (keyboardChange !== 'm') {
39826                 $scope.minutes = pad(minutes);
39827               }
39828               $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
39829
39830               if (keyboardChange !== 's') {
39831                 $scope.seconds = pad(seconds);
39832               }
39833               $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
39834             }
39835           }
39836
39837           function addSecondsToSelected(seconds) {
39838             selected = addSeconds(selected, seconds);
39839             refresh();
39840           }
39841
39842           function addMinutes(selected, minutes) {
39843             return addSeconds(selected, minutes*60);
39844           }
39845
39846           function addSeconds(date, seconds) {
39847             var dt = new Date(date.getTime() + seconds * 1000);
39848             var newDate = new Date(date);
39849             newDate.setHours(dt.getHours(), dt.getMinutes(), dt.getSeconds());
39850             return newDate;
39851           }
39852
39853           $scope.showSpinners = angular.isDefined($attrs.showSpinners) ?
39854             $scope.$parent.$eval($attrs.showSpinners) : timepickerConfig.showSpinners;
39855
39856           $scope.incrementHours = function() {
39857             if (!$scope.noIncrementHours()) {
39858               addSecondsToSelected(hourStep * 60 * 60);
39859             }
39860           };
39861
39862           $scope.decrementHours = function() {
39863             if (!$scope.noDecrementHours()) {
39864               addSecondsToSelected(-hourStep * 60 * 60);
39865             }
39866           };
39867
39868           $scope.incrementMinutes = function() {
39869             if (!$scope.noIncrementMinutes()) {
39870               addSecondsToSelected(minuteStep * 60);
39871             }
39872           };
39873
39874           $scope.decrementMinutes = function() {
39875             if (!$scope.noDecrementMinutes()) {
39876               addSecondsToSelected(-minuteStep * 60);
39877             }
39878           };
39879
39880           $scope.incrementSeconds = function() {
39881             if (!$scope.noIncrementSeconds()) {
39882               addSecondsToSelected(secondStep);
39883             }
39884           };
39885
39886           $scope.decrementSeconds = function() {
39887             if (!$scope.noDecrementSeconds()) {
39888               addSecondsToSelected(-secondStep);
39889             }
39890           };
39891
39892           $scope.toggleMeridian = function() {
39893             var minutes = getMinutesFromTemplate(),
39894                 hours = getHoursFromTemplate();
39895
39896             if (!$scope.noToggleMeridian()) {
39897               if (angular.isDefined(minutes) && angular.isDefined(hours)) {
39898                 addSecondsToSelected(12 * 60 * (selected.getHours() < 12 ? 60 : -60));
39899               } else {
39900                 $scope.meridian = $scope.meridian === meridians[0] ? meridians[1] : meridians[0];
39901               }
39902             }
39903           };
39904
39905           $scope.blur = function() {
39906             ngModelCtrl.$setTouched();
39907           };
39908         }])
39909
39910         .directive('uibTimepicker', function() {
39911           return {
39912             require: ['uibTimepicker', '?^ngModel'],
39913             controller: 'UibTimepickerController',
39914             controllerAs: 'timepicker',
39915             replace: true,
39916             scope: {},
39917             templateUrl: function(element, attrs) {
39918               return attrs.templateUrl || 'uib/template/timepicker/timepicker.html';
39919             },
39920             link: function(scope, element, attrs, ctrls) {
39921               var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
39922
39923               if (ngModelCtrl) {
39924                 timepickerCtrl.init(ngModelCtrl, element.find('input'));
39925               }
39926             }
39927           };
39928         });
39929
39930         angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap.position'])
39931
39932         /**
39933          * A helper service that can parse typeahead's syntax (string provided by users)
39934          * Extracted to a separate service for ease of unit testing
39935          */
39936           .factory('uibTypeaheadParser', ['$parse', function($parse) {
39937             //                      00000111000000000000022200000000000000003333333333333330000000000044000
39938             var TYPEAHEAD_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;
39939             return {
39940               parse: function(input) {
39941                 var match = input.match(TYPEAHEAD_REGEXP);
39942                 if (!match) {
39943                   throw new Error(
39944                     'Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_"' +
39945                       ' but got "' + input + '".');
39946                 }
39947
39948                 return {
39949                   itemName: match[3],
39950                   source: $parse(match[4]),
39951                   viewMapper: $parse(match[2] || match[1]),
39952                   modelMapper: $parse(match[1])
39953                 };
39954               }
39955             };
39956           }])
39957
39958           .controller('UibTypeaheadController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$q', '$timeout', '$document', '$window', '$rootScope', '$$debounce', '$uibPosition', 'uibTypeaheadParser',
39959             function(originalScope, element, attrs, $compile, $parse, $q, $timeout, $document, $window, $rootScope, $$debounce, $position, typeaheadParser) {
39960             var HOT_KEYS = [9, 13, 27, 38, 40];
39961             var eventDebounceTime = 200;
39962             var modelCtrl, ngModelOptions;
39963             //SUPPORTED ATTRIBUTES (OPTIONS)
39964
39965             //minimal no of characters that needs to be entered before typeahead kicks-in
39966             var minLength = originalScope.$eval(attrs.typeaheadMinLength);
39967             if (!minLength && minLength !== 0) {
39968               minLength = 1;
39969             }
39970
39971             //minimal wait time after last character typed before typeahead kicks-in
39972             var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
39973
39974             //should it restrict model values to the ones selected from the popup only?
39975             var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
39976             originalScope.$watch(attrs.typeaheadEditable, function (newVal) {
39977               isEditable = newVal !== false;
39978             });
39979
39980             //binding to a variable that indicates if matches are being retrieved asynchronously
39981             var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
39982
39983             //a callback executed when a match is selected
39984             var onSelectCallback = $parse(attrs.typeaheadOnSelect);
39985
39986             //should it select highlighted popup value when losing focus?
39987             var isSelectOnBlur = angular.isDefined(attrs.typeaheadSelectOnBlur) ? originalScope.$eval(attrs.typeaheadSelectOnBlur) : false;
39988
39989             //binding to a variable that indicates if there were no results after the query is completed
39990             var isNoResultsSetter = $parse(attrs.typeaheadNoResults).assign || angular.noop;
39991
39992             var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
39993
39994             var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
39995
39996             var appendTo = attrs.typeaheadAppendTo ?
39997               originalScope.$eval(attrs.typeaheadAppendTo) : null;
39998
39999             var focusFirst = originalScope.$eval(attrs.typeaheadFocusFirst) !== false;
40000
40001             //If input matches an item of the list exactly, select it automatically
40002             var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;
40003
40004             //binding to a variable that indicates if dropdown is open
40005             var isOpenSetter = $parse(attrs.typeaheadIsOpen).assign || angular.noop;
40006
40007             var showHint = originalScope.$eval(attrs.typeaheadShowHint) || false;
40008
40009             //INTERNAL VARIABLES
40010
40011             //model setter executed upon match selection
40012             var parsedModel = $parse(attrs.ngModel);
40013             var invokeModelSetter = $parse(attrs.ngModel + '($$$p)');
40014             var $setModelValue = function(scope, newValue) {
40015               if (angular.isFunction(parsedModel(originalScope)) &&
40016                 ngModelOptions && ngModelOptions.$options && ngModelOptions.$options.getterSetter) {
40017                 return invokeModelSetter(scope, {$$$p: newValue});
40018               }
40019
40020               return parsedModel.assign(scope, newValue);
40021             };
40022
40023             //expressions used by typeahead
40024             var parserResult = typeaheadParser.parse(attrs.uibTypeahead);
40025
40026             var hasFocus;
40027
40028             //Used to avoid bug in iOS webview where iOS keyboard does not fire
40029             //mousedown & mouseup events
40030             //Issue #3699
40031             var selected;
40032
40033             //create a child scope for the typeahead directive so we are not polluting original scope
40034             //with typeahead-specific data (matches, query etc.)
40035             var scope = originalScope.$new();
40036             var offDestroy = originalScope.$on('$destroy', function() {
40037               scope.$destroy();
40038             });
40039             scope.$on('$destroy', offDestroy);
40040
40041             // WAI-ARIA
40042             var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
40043             element.attr({
40044               'aria-autocomplete': 'list',
40045               'aria-expanded': false,
40046               'aria-owns': popupId
40047             });
40048
40049             var inputsContainer, hintInputElem;
40050             //add read-only input to show hint
40051             if (showHint) {
40052               inputsContainer = angular.element('<div></div>');
40053               inputsContainer.css('position', 'relative');
40054               element.after(inputsContainer);
40055               hintInputElem = element.clone();
40056               hintInputElem.attr('placeholder', '');
40057               hintInputElem.val('');
40058               hintInputElem.css({
40059                 'position': 'absolute',
40060                 'top': '0px',
40061                 'left': '0px',
40062                 'border-color': 'transparent',
40063                 'box-shadow': 'none',
40064                 'opacity': 1,
40065                 'background': 'none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255)',
40066                 'color': '#999'
40067               });
40068               element.css({
40069                 'position': 'relative',
40070                 'vertical-align': 'top',
40071                 'background-color': 'transparent'
40072               });
40073               inputsContainer.append(hintInputElem);
40074               hintInputElem.after(element);
40075             }
40076
40077             //pop-up element used to display matches
40078             var popUpEl = angular.element('<div uib-typeahead-popup></div>');
40079             popUpEl.attr({
40080               id: popupId,
40081               matches: 'matches',
40082               active: 'activeIdx',
40083               select: 'select(activeIdx, evt)',
40084               'move-in-progress': 'moveInProgress',
40085               query: 'query',
40086               position: 'position',
40087               'assign-is-open': 'assignIsOpen(isOpen)',
40088               debounce: 'debounceUpdate'
40089             });
40090             //custom item template
40091             if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
40092               popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
40093             }
40094
40095             if (angular.isDefined(attrs.typeaheadPopupTemplateUrl)) {
40096               popUpEl.attr('popup-template-url', attrs.typeaheadPopupTemplateUrl);
40097             }
40098
40099             var resetHint = function() {
40100               if (showHint) {
40101                 hintInputElem.val('');
40102               }
40103             };
40104
40105             var resetMatches = function() {
40106               scope.matches = [];
40107               scope.activeIdx = -1;
40108               element.attr('aria-expanded', false);
40109               resetHint();
40110             };
40111
40112             var getMatchId = function(index) {
40113               return popupId + '-option-' + index;
40114             };
40115
40116             // Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
40117             // This attribute is added or removed automatically when the `activeIdx` changes.
40118             scope.$watch('activeIdx', function(index) {
40119               if (index < 0) {
40120                 element.removeAttr('aria-activedescendant');
40121               } else {
40122                 element.attr('aria-activedescendant', getMatchId(index));
40123               }
40124             });
40125
40126             var inputIsExactMatch = function(inputValue, index) {
40127               if (scope.matches.length > index && inputValue) {
40128                 return inputValue.toUpperCase() === scope.matches[index].label.toUpperCase();
40129               }
40130
40131               return false;
40132             };
40133
40134             var getMatchesAsync = function(inputValue, evt) {
40135               var locals = {$viewValue: inputValue};
40136               isLoadingSetter(originalScope, true);
40137               isNoResultsSetter(originalScope, false);
40138               $q.when(parserResult.source(originalScope, locals)).then(function(matches) {
40139                 //it might happen that several async queries were in progress if a user were typing fast
40140                 //but we are interested only in responses that correspond to the current view value
40141                 var onCurrentRequest = inputValue === modelCtrl.$viewValue;
40142                 if (onCurrentRequest && hasFocus) {
40143                   if (matches && matches.length > 0) {
40144                     scope.activeIdx = focusFirst ? 0 : -1;
40145                     isNoResultsSetter(originalScope, false);
40146                     scope.matches.length = 0;
40147
40148                     //transform labels
40149                     for (var i = 0; i < matches.length; i++) {
40150                       locals[parserResult.itemName] = matches[i];
40151                       scope.matches.push({
40152                         id: getMatchId(i),
40153                         label: parserResult.viewMapper(scope, locals),
40154                         model: matches[i]
40155                       });
40156                     }
40157
40158                     scope.query = inputValue;
40159                     //position pop-up with matches - we need to re-calculate its position each time we are opening a window
40160                     //with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
40161                     //due to other elements being rendered
40162                     recalculatePosition();
40163
40164                     element.attr('aria-expanded', true);
40165
40166                     //Select the single remaining option if user input matches
40167                     if (selectOnExact && scope.matches.length === 1 && inputIsExactMatch(inputValue, 0)) {
40168                       if (angular.isNumber(scope.debounceUpdate) || angular.isObject(scope.debounceUpdate)) {
40169                         $$debounce(function() {
40170                           scope.select(0, evt);
40171                         }, angular.isNumber(scope.debounceUpdate) ? scope.debounceUpdate : scope.debounceUpdate['default']);
40172                       } else {
40173                         scope.select(0, evt);
40174                       }
40175                     }
40176
40177                     if (showHint) {
40178                       var firstLabel = scope.matches[0].label;
40179                       if (inputValue.length > 0 && firstLabel.slice(0, inputValue.length).toUpperCase() === inputValue.toUpperCase()) {
40180                         hintInputElem.val(inputValue + firstLabel.slice(inputValue.length));
40181                       }
40182                       else {
40183                         hintInputElem.val('');
40184                       }
40185                     }
40186                   } else {
40187                     resetMatches();
40188                     isNoResultsSetter(originalScope, true);
40189                   }
40190                 }
40191                 if (onCurrentRequest) {
40192                   isLoadingSetter(originalScope, false);
40193                 }
40194               }, function() {
40195                 resetMatches();
40196                 isLoadingSetter(originalScope, false);
40197                 isNoResultsSetter(originalScope, true);
40198               });
40199             };
40200
40201             // bind events only if appendToBody params exist - performance feature
40202             if (appendToBody) {
40203               angular.element($window).on('resize', fireRecalculating);
40204               $document.find('body').on('scroll', fireRecalculating);
40205             }
40206
40207             // Declare the debounced function outside recalculating for
40208             // proper debouncing
40209             var debouncedRecalculate = $$debounce(function() {
40210               // if popup is visible
40211               if (scope.matches.length) {
40212                 recalculatePosition();
40213               }
40214
40215               scope.moveInProgress = false;
40216             }, eventDebounceTime);
40217
40218             // Default progress type
40219             scope.moveInProgress = false;
40220
40221             function fireRecalculating() {
40222               if (!scope.moveInProgress) {
40223                 scope.moveInProgress = true;
40224                 scope.$digest();
40225               }
40226
40227               debouncedRecalculate();
40228             }
40229
40230             // recalculate actual position and set new values to scope
40231             // after digest loop is popup in right position
40232             function recalculatePosition() {
40233               scope.position = appendToBody ? $position.offset(element) : $position.position(element);
40234               scope.position.top += element.prop('offsetHeight');
40235             }
40236
40237             //we need to propagate user's query so we can higlight matches
40238             scope.query = undefined;
40239
40240             //Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
40241             var timeoutPromise;
40242
40243             var scheduleSearchWithTimeout = function(inputValue) {
40244               timeoutPromise = $timeout(function() {
40245                 getMatchesAsync(inputValue);
40246               }, waitTime);
40247             };
40248
40249             var cancelPreviousTimeout = function() {
40250               if (timeoutPromise) {
40251                 $timeout.cancel(timeoutPromise);
40252               }
40253             };
40254
40255             resetMatches();
40256
40257             scope.assignIsOpen = function (isOpen) {
40258               isOpenSetter(originalScope, isOpen);
40259             };
40260
40261             scope.select = function(activeIdx, evt) {
40262               //called from within the $digest() cycle
40263               var locals = {};
40264               var model, item;
40265
40266               selected = true;
40267               locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
40268               model = parserResult.modelMapper(originalScope, locals);
40269               $setModelValue(originalScope, model);
40270               modelCtrl.$setValidity('editable', true);
40271               modelCtrl.$setValidity('parse', true);
40272
40273               onSelectCallback(originalScope, {
40274                 $item: item,
40275                 $model: model,
40276                 $label: parserResult.viewMapper(originalScope, locals),
40277                 $event: evt
40278               });
40279
40280               resetMatches();
40281
40282               //return focus to the input element if a match was selected via a mouse click event
40283               // use timeout to avoid $rootScope:inprog error
40284               if (scope.$eval(attrs.typeaheadFocusOnSelect) !== false) {
40285                 $timeout(function() { element[0].focus(); }, 0, false);
40286               }
40287             };
40288
40289             //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
40290             element.on('keydown', function(evt) {
40291               //typeahead is open and an "interesting" key was pressed
40292               if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
40293                 return;
40294               }
40295
40296               // if there's nothing selected (i.e. focusFirst) and enter or tab is hit, clear the results
40297               if (scope.activeIdx === -1 && (evt.which === 9 || evt.which === 13)) {
40298                 resetMatches();
40299                 scope.$digest();
40300                 return;
40301               }
40302
40303               evt.preventDefault();
40304
40305               switch (evt.which) {
40306                 case 9:
40307                 case 13:
40308                   scope.$apply(function () {
40309                     if (angular.isNumber(scope.debounceUpdate) || angular.isObject(scope.debounceUpdate)) {
40310                       $$debounce(function() {
40311                         scope.select(scope.activeIdx, evt);
40312                       }, angular.isNumber(scope.debounceUpdate) ? scope.debounceUpdate : scope.debounceUpdate['default']);
40313                     } else {
40314                       scope.select(scope.activeIdx, evt);
40315                     }
40316                   });
40317                   break;
40318                 case 27:
40319                   evt.stopPropagation();
40320
40321                   resetMatches();
40322                   scope.$digest();
40323                   break;
40324                 case 38:
40325                   scope.activeIdx = (scope.activeIdx > 0 ? scope.activeIdx : scope.matches.length) - 1;
40326                   scope.$digest();
40327                   popUpEl.find('li')[scope.activeIdx].scrollIntoView(false);
40328                   break;
40329                 case 40:
40330                   scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
40331                   scope.$digest();
40332                   popUpEl.find('li')[scope.activeIdx].scrollIntoView(false);
40333                   break;
40334               }
40335             });
40336
40337             element.bind('focus', function (evt) {
40338               hasFocus = true;
40339               if (minLength === 0 && !modelCtrl.$viewValue) {
40340                 $timeout(function() {
40341                   getMatchesAsync(modelCtrl.$viewValue, evt);
40342                 }, 0);
40343               }
40344             });
40345
40346             element.bind('blur', function(evt) {
40347               if (isSelectOnBlur && scope.matches.length && scope.activeIdx !== -1 && !selected) {
40348                 selected = true;
40349                 scope.$apply(function() {
40350                   if (angular.isObject(scope.debounceUpdate) && angular.isNumber(scope.debounceUpdate.blur)) {
40351                     $$debounce(function() {
40352                       scope.select(scope.activeIdx, evt);
40353                     }, scope.debounceUpdate.blur);
40354                   } else {
40355                     scope.select(scope.activeIdx, evt);
40356                   }
40357                 });
40358               }
40359               if (!isEditable && modelCtrl.$error.editable) {
40360                 modelCtrl.$viewValue = '';
40361                 element.val('');
40362               }
40363               hasFocus = false;
40364               selected = false;
40365             });
40366
40367             // Keep reference to click handler to unbind it.
40368             var dismissClickHandler = function(evt) {
40369               // Issue #3973
40370               // Firefox treats right click as a click on document
40371               if (element[0] !== evt.target && evt.which !== 3 && scope.matches.length !== 0) {
40372                 resetMatches();
40373                 if (!$rootScope.$$phase) {
40374                   scope.$digest();
40375                 }
40376               }
40377             };
40378
40379             $document.on('click', dismissClickHandler);
40380
40381             originalScope.$on('$destroy', function() {
40382               $document.off('click', dismissClickHandler);
40383               if (appendToBody || appendTo) {
40384                 $popup.remove();
40385               }
40386
40387               if (appendToBody) {
40388                 angular.element($window).off('resize', fireRecalculating);
40389                 $document.find('body').off('scroll', fireRecalculating);
40390               }
40391               // Prevent jQuery cache memory leak
40392               popUpEl.remove();
40393
40394               if (showHint) {
40395                   inputsContainer.remove();
40396               }
40397             });
40398
40399             var $popup = $compile(popUpEl)(scope);
40400
40401             if (appendToBody) {
40402               $document.find('body').append($popup);
40403             } else if (appendTo) {
40404               angular.element(appendTo).eq(0).append($popup);
40405             } else {
40406               element.after($popup);
40407             }
40408
40409             this.init = function(_modelCtrl, _ngModelOptions) {
40410               modelCtrl = _modelCtrl;
40411               ngModelOptions = _ngModelOptions;
40412
40413               scope.debounceUpdate = modelCtrl.$options && $parse(modelCtrl.$options.debounce)(originalScope);
40414
40415               //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
40416               //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
40417               modelCtrl.$parsers.unshift(function(inputValue) {
40418                 hasFocus = true;
40419
40420                 if (minLength === 0 || inputValue && inputValue.length >= minLength) {
40421                   if (waitTime > 0) {
40422                     cancelPreviousTimeout();
40423                     scheduleSearchWithTimeout(inputValue);
40424                   } else {
40425                     getMatchesAsync(inputValue);
40426                   }
40427                 } else {
40428                   isLoadingSetter(originalScope, false);
40429                   cancelPreviousTimeout();
40430                   resetMatches();
40431                 }
40432
40433                 if (isEditable) {
40434                   return inputValue;
40435                 }
40436
40437                 if (!inputValue) {
40438                   // Reset in case user had typed something previously.
40439                   modelCtrl.$setValidity('editable', true);
40440                   return null;
40441                 }
40442
40443                 modelCtrl.$setValidity('editable', false);
40444                 return undefined;
40445               });
40446
40447               modelCtrl.$formatters.push(function(modelValue) {
40448                 var candidateViewValue, emptyViewValue;
40449                 var locals = {};
40450
40451                 // The validity may be set to false via $parsers (see above) if
40452                 // the model is restricted to selected values. If the model
40453                 // is set manually it is considered to be valid.
40454                 if (!isEditable) {
40455                   modelCtrl.$setValidity('editable', true);
40456                 }
40457
40458                 if (inputFormatter) {
40459                   locals.$model = modelValue;
40460                   return inputFormatter(originalScope, locals);
40461                 }
40462
40463                 //it might happen that we don't have enough info to properly render input value
40464                 //we need to check for this situation and simply return model value if we can't apply custom formatting
40465                 locals[parserResult.itemName] = modelValue;
40466                 candidateViewValue = parserResult.viewMapper(originalScope, locals);
40467                 locals[parserResult.itemName] = undefined;
40468                 emptyViewValue = parserResult.viewMapper(originalScope, locals);
40469
40470                 return candidateViewValue !== emptyViewValue ? candidateViewValue : modelValue;
40471               });
40472             };
40473           }])
40474
40475           .directive('uibTypeahead', function() {
40476             return {
40477               controller: 'UibTypeaheadController',
40478               require: ['ngModel', '^?ngModelOptions', 'uibTypeahead'],
40479               link: function(originalScope, element, attrs, ctrls) {
40480                 ctrls[2].init(ctrls[0], ctrls[1]);
40481               }
40482             };
40483           })
40484
40485           .directive('uibTypeaheadPopup', ['$$debounce', function($$debounce) {
40486             return {
40487               scope: {
40488                 matches: '=',
40489                 query: '=',
40490                 active: '=',
40491                 position: '&',
40492                 moveInProgress: '=',
40493                 select: '&',
40494                 assignIsOpen: '&',
40495                 debounce: '&'
40496               },
40497               replace: true,
40498               templateUrl: function(element, attrs) {
40499                 return attrs.popupTemplateUrl || 'uib/template/typeahead/typeahead-popup.html';
40500               },
40501               link: function(scope, element, attrs) {
40502                 scope.templateUrl = attrs.templateUrl;
40503
40504                 scope.isOpen = function() {
40505                   var isDropdownOpen = scope.matches.length > 0;
40506                   scope.assignIsOpen({ isOpen: isDropdownOpen });
40507                   return isDropdownOpen;
40508                 };
40509
40510                 scope.isActive = function(matchIdx) {
40511                   return scope.active === matchIdx;
40512                 };
40513
40514                 scope.selectActive = function(matchIdx) {
40515                   scope.active = matchIdx;
40516                 };
40517
40518                 scope.selectMatch = function(activeIdx, evt) {
40519                   var debounce = scope.debounce();
40520                   if (angular.isNumber(debounce) || angular.isObject(debounce)) {
40521                     $$debounce(function() {
40522                       scope.select({activeIdx: activeIdx, evt: evt});
40523                     }, angular.isNumber(debounce) ? debounce : debounce['default']);
40524                   } else {
40525                     scope.select({activeIdx: activeIdx, evt: evt});
40526                   }
40527                 };
40528               }
40529             };
40530           }])
40531
40532           .directive('uibTypeaheadMatch', ['$templateRequest', '$compile', '$parse', function($templateRequest, $compile, $parse) {
40533             return {
40534               scope: {
40535                 index: '=',
40536                 match: '=',
40537                 query: '='
40538               },
40539               link: function(scope, element, attrs) {
40540                 var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'uib/template/typeahead/typeahead-match.html';
40541                 $templateRequest(tplUrl).then(function(tplContent) {
40542                   var tplEl = angular.element(tplContent.trim());
40543                   element.replaceWith(tplEl);
40544                   $compile(tplEl)(scope);
40545                 });
40546               }
40547             };
40548           }])
40549
40550           .filter('uibTypeaheadHighlight', ['$sce', '$injector', '$log', function($sce, $injector, $log) {
40551             var isSanitizePresent;
40552             isSanitizePresent = $injector.has('$sanitize');
40553
40554             function escapeRegexp(queryToEscape) {
40555               // Regex: capture the whole query string and replace it with the string that will be used to match
40556               // the results, for example if the capture is "a" the result will be \a
40557               return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
40558             }
40559
40560             function containsHtml(matchItem) {
40561               return /<.*>/g.test(matchItem);
40562             }
40563
40564             return function(matchItem, query) {
40565               if (!isSanitizePresent && containsHtml(matchItem)) {
40566                 $log.warn('Unsafe use of typeahead please use ngSanitize'); // Warn the user about the danger
40567               }
40568               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
40569               if (!isSanitizePresent) {
40570                 matchItem = $sce.trustAsHtml(matchItem); // If $sanitize is not present we pack the string in a $sce object for the ng-bind-html directive
40571               }
40572               return matchItem;
40573             };
40574           }]);
40575
40576         angular.module("uib/template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
40577           $templateCache.put("uib/template/accordion/accordion-group.html",
40578             "<div class=\"panel\" ng-class=\"panelClass || 'panel-default'\">\n" +
40579             "  <div class=\"panel-heading\" ng-keypress=\"toggleOpen($event)\">\n" +
40580             "    <h4 class=\"panel-title\">\n" +
40581             "      <div tabindex=\"0\" class=\"accordion-toggle\" ng-click=\"toggleOpen()\" uib-accordion-transclude=\"heading\"><span ng-class=\"{'text-muted': isDisabled}\">{{heading}}</span></div>\n" +
40582             "    </h4>\n" +
40583             "  </div>\n" +
40584             "  <div class=\"panel-collapse collapse\" uib-collapse=\"!isOpen\">\n" +
40585             "     <div class=\"panel-body\" ng-transclude></div>\n" +
40586             "  </div>\n" +
40587             "</div>\n" +
40588             "");
40589         }]);
40590
40591         angular.module("uib/template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
40592           $templateCache.put("uib/template/accordion/accordion.html",
40593             "<div class=\"panel-group\" ng-transclude></div>");
40594         }]);
40595
40596         angular.module("uib/template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
40597           $templateCache.put("uib/template/alert/alert.html",
40598             "<div class=\"alert\" ng-class=\"['alert-' + (type || 'warning'), closeable ? 'alert-dismissible' : null]\" role=\"alert\">\n" +
40599             "    <button ng-show=\"closeable\" type=\"button\" class=\"close\" ng-click=\"close({$event: $event})\">\n" +
40600             "        <span aria-hidden=\"true\">&times;</span>\n" +
40601             "        <span class=\"sr-only\">Close</span>\n" +
40602             "    </button>\n" +
40603             "    <div ng-transclude></div>\n" +
40604             "</div>\n" +
40605             "");
40606         }]);
40607
40608         angular.module("uib/template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) {
40609           $templateCache.put("uib/template/carousel/carousel.html",
40610             "<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\">\n" +
40611             "  <div class=\"carousel-inner\" ng-transclude></div>\n" +
40612             "  <a role=\"button\" href class=\"left carousel-control\" ng-click=\"prev()\" ng-show=\"slides.length > 1\">\n" +
40613             "    <span aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-left\"></span>\n" +
40614             "    <span class=\"sr-only\">previous</span>\n" +
40615             "  </a>\n" +
40616             "  <a role=\"button\" href class=\"right carousel-control\" ng-click=\"next()\" ng-show=\"slides.length > 1\">\n" +
40617             "    <span aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-right\"></span>\n" +
40618             "    <span class=\"sr-only\">next</span>\n" +
40619             "  </a>\n" +
40620             "  <ol class=\"carousel-indicators\" ng-show=\"slides.length > 1\">\n" +
40621             "    <li ng-repeat=\"slide in slides | orderBy:indexOfSlide track by $index\" ng-class=\"{ active: isActive(slide) }\" ng-click=\"select(slide)\">\n" +
40622             "      <span class=\"sr-only\">slide {{ $index + 1 }} of {{ slides.length }}<span ng-if=\"isActive(slide)\">, currently active</span></span>\n" +
40623             "    </li>\n" +
40624             "  </ol>\n" +
40625             "</div>");
40626         }]);
40627
40628         angular.module("uib/template/carousel/slide.html", []).run(["$templateCache", function($templateCache) {
40629           $templateCache.put("uib/template/carousel/slide.html",
40630             "<div ng-class=\"{\n" +
40631             "    'active': active\n" +
40632             "  }\" class=\"item text-center\" ng-transclude></div>\n" +
40633             "");
40634         }]);
40635
40636         angular.module("uib/template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
40637           $templateCache.put("uib/template/datepicker/datepicker.html",
40638             "<div class=\"uib-datepicker\" ng-switch=\"datepickerMode\" role=\"application\" ng-keydown=\"keydown($event)\">\n" +
40639             "  <uib-daypicker ng-switch-when=\"day\" tabindex=\"0\"></uib-daypicker>\n" +
40640             "  <uib-monthpicker ng-switch-when=\"month\" tabindex=\"0\"></uib-monthpicker>\n" +
40641             "  <uib-yearpicker ng-switch-when=\"year\" tabindex=\"0\"></uib-yearpicker>\n" +
40642             "</div>");
40643         }]);
40644
40645         angular.module("uib/template/datepicker/day.html", []).run(["$templateCache", function($templateCache) {
40646           $templateCache.put("uib/template/datepicker/day.html",
40647             "<table class=\"uib-daypicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
40648             "  <thead>\n" +
40649             "    <tr>\n" +
40650             "      <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" +
40651             "      <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" +
40652             "      <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" +
40653             "    </tr>\n" +
40654             "    <tr>\n" +
40655             "      <th ng-if=\"showWeeks\" class=\"text-center\"></th>\n" +
40656             "      <th ng-repeat=\"label in ::labels track by $index\" class=\"text-center\"><small aria-label=\"{{::label.full}}\">{{::label.abbr}}</small></th>\n" +
40657             "    </tr>\n" +
40658             "  </thead>\n" +
40659             "  <tbody>\n" +
40660             "    <tr class=\"uib-weeks\" ng-repeat=\"row in rows track by $index\">\n" +
40661             "      <td ng-if=\"showWeeks\" class=\"text-center h6\"><em>{{ weekNumbers[$index] }}</em></td>\n" +
40662             "      <td ng-repeat=\"dt in row\" class=\"uib-day text-center\" role=\"gridcell\"\n" +
40663             "        id=\"{{::dt.uid}}\"\n" +
40664             "        ng-class=\"::dt.customClass\">\n" +
40665             "        <button type=\"button\" style=\"min-width:100%;\" class=\"btn btn-default btn-sm\"\n" +
40666             "          uib-is-class=\"\n" +
40667             "            'btn-info' for selectedDt,\n" +
40668             "            'active' for activeDt\n" +
40669             "            on dt\"\n" +
40670             "          ng-click=\"select(dt.date)\"\n" +
40671             "          ng-disabled=\"::dt.disabled\"\n" +
40672             "          tabindex=\"-1\"><span ng-class=\"::{'text-muted': dt.secondary, 'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
40673             "      </td>\n" +
40674             "    </tr>\n" +
40675             "  </tbody>\n" +
40676             "</table>\n" +
40677             "");
40678         }]);
40679
40680         angular.module("uib/template/datepicker/month.html", []).run(["$templateCache", function($templateCache) {
40681           $templateCache.put("uib/template/datepicker/month.html",
40682             "<table class=\"uib-monthpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
40683             "  <thead>\n" +
40684             "    <tr>\n" +
40685             "      <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" +
40686             "      <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" +
40687             "      <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" +
40688             "    </tr>\n" +
40689             "  </thead>\n" +
40690             "  <tbody>\n" +
40691             "    <tr class=\"uib-months\" ng-repeat=\"row in rows track by $index\">\n" +
40692             "      <td ng-repeat=\"dt in row\" class=\"uib-month text-center\" role=\"gridcell\"\n" +
40693             "        id=\"{{::dt.uid}}\"\n" +
40694             "        ng-class=\"::dt.customClass\">\n" +
40695             "        <button type=\"button\" style=\"min-width:100%;\" class=\"btn btn-default\"\n" +
40696             "          uib-is-class=\"\n" +
40697             "            'btn-info' for selectedDt,\n" +
40698             "            'active' for activeDt\n" +
40699             "            on dt\"\n" +
40700             "          ng-click=\"select(dt.date)\"\n" +
40701             "          ng-disabled=\"::dt.disabled\"\n" +
40702             "          tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
40703             "      </td>\n" +
40704             "    </tr>\n" +
40705             "  </tbody>\n" +
40706             "</table>\n" +
40707             "");
40708         }]);
40709
40710         angular.module("uib/template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) {
40711           $templateCache.put("uib/template/datepicker/popup.html",
40712             "<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" +
40713             "   <li ng-transclude></li>\n" +
40714             "   <li ng-if=\"showButtonBar\" style=\"padding:10px 9px 2px\" class=\"uib-button-bar\">\n" +
40715             "           <span class=\"btn-group pull-left\">\n" +
40716             "                   <button type=\"button\" class=\"btn btn-sm btn-info uib-datepicker-current\" ng-click=\"select('today')\" ng-disabled=\"isDisabled('today')\">{{ getText('current') }}</button>\n" +
40717             "                   <button type=\"button\" class=\"btn btn-sm btn-danger uib-clear\" ng-click=\"select(null)\">{{ getText('clear') }}</button>\n" +
40718             "           </span>\n" +
40719             "           <button type=\"button\" class=\"btn btn-sm btn-success pull-right uib-close\" ng-click=\"close()\">{{ getText('close') }}</button>\n" +
40720             "   </li>\n" +
40721             "</ul>\n" +
40722             "");
40723         }]);
40724
40725         angular.module("uib/template/datepicker/year.html", []).run(["$templateCache", function($templateCache) {
40726           $templateCache.put("uib/template/datepicker/year.html",
40727             "<table class=\"uib-yearpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
40728             "  <thead>\n" +
40729             "    <tr>\n" +
40730             "      <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" +
40731             "      <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" +
40732             "      <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" +
40733             "    </tr>\n" +
40734             "  </thead>\n" +
40735             "  <tbody>\n" +
40736             "    <tr class=\"uib-years\" ng-repeat=\"row in rows track by $index\">\n" +
40737             "      <td ng-repeat=\"dt in row\" class=\"uib-year text-center\" role=\"gridcell\"\n" +
40738             "        id=\"{{::dt.uid}}\"\n" +
40739             "        ng-class=\"::dt.customClass\">\n" +
40740             "        <button type=\"button\" style=\"min-width:100%;\" class=\"btn btn-default\"\n" +
40741             "          uib-is-class=\"\n" +
40742             "            'btn-info' for selectedDt,\n" +
40743             "            'active' for activeDt\n" +
40744             "            on dt\"\n" +
40745             "          ng-click=\"select(dt.date)\"\n" +
40746             "          ng-disabled=\"::dt.disabled\"\n" +
40747             "          tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
40748             "      </td>\n" +
40749             "    </tr>\n" +
40750             "  </tbody>\n" +
40751             "</table>\n" +
40752             "");
40753         }]);
40754
40755         angular.module("uib/template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
40756           $templateCache.put("uib/template/modal/backdrop.html",
40757             "<div class=\"modal-backdrop\"\n" +
40758             "     uib-modal-animation-class=\"fade\"\n" +
40759             "     modal-in-class=\"in\"\n" +
40760             "     ng-style=\"{'z-index': 1040 + (index && 1 || 0) + index*10}\"\n" +
40761             "></div>\n" +
40762             "");
40763         }]);
40764
40765         angular.module("uib/template/modal/window.html", []).run(["$templateCache", function($templateCache) {
40766           $templateCache.put("uib/template/modal/window.html",
40767             "<div modal-render=\"{{$isRendered}}\" tabindex=\"-1\" role=\"dialog\" class=\"modal\"\n" +
40768             "    uib-modal-animation-class=\"fade\"\n" +
40769             "    modal-in-class=\"in\"\n" +
40770             "    ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\">\n" +
40771             "    <div class=\"modal-dialog\" ng-class=\"size ? 'modal-' + size : ''\"><div class=\"modal-content\" uib-modal-transclude></div></div>\n" +
40772             "</div>\n" +
40773             "");
40774         }]);
40775
40776         angular.module("uib/template/pager/pager.html", []).run(["$templateCache", function($templateCache) {
40777           $templateCache.put("uib/template/pager/pager.html",
40778             "<ul class=\"pager\">\n" +
40779             "  <li ng-class=\"{disabled: noPrevious()||ngDisabled, previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
40780             "  <li ng-class=\"{disabled: noNext()||ngDisabled, next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
40781             "</ul>\n" +
40782             "");
40783         }]);
40784
40785         angular.module("uib/template/pagination/pager.html", []).run(["$templateCache", function($templateCache) {
40786           $templateCache.put("uib/template/pagination/pager.html",
40787             "<ul class=\"pager\">\n" +
40788             "  <li ng-class=\"{disabled: noPrevious()||ngDisabled, previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
40789             "  <li ng-class=\"{disabled: noNext()||ngDisabled, next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
40790             "</ul>\n" +
40791             "");
40792         }]);
40793
40794         angular.module("uib/template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
40795           $templateCache.put("uib/template/pagination/pagination.html",
40796             "<ul class=\"pagination\">\n" +
40797             "  <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noPrevious()||ngDisabled}\" class=\"pagination-first\"><a href ng-click=\"selectPage(1, $event)\">{{::getText('first')}}</a></li>\n" +
40798             "  <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" +
40799             "  <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" +
40800             "  <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" +
40801             "  <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noNext()||ngDisabled}\" class=\"pagination-last\"><a href ng-click=\"selectPage(totalPages, $event)\">{{::getText('last')}}</a></li>\n" +
40802             "</ul>\n" +
40803             "");
40804         }]);
40805
40806         angular.module("uib/template/tooltip/tooltip-html-popup.html", []).run(["$templateCache", function($templateCache) {
40807           $templateCache.put("uib/template/tooltip/tooltip-html-popup.html",
40808             "<div class=\"tooltip\"\n" +
40809             "  tooltip-animation-class=\"fade\"\n" +
40810             "  uib-tooltip-classes\n" +
40811             "  ng-class=\"{ in: isOpen() }\">\n" +
40812             "  <div class=\"tooltip-arrow\"></div>\n" +
40813             "  <div class=\"tooltip-inner\" ng-bind-html=\"contentExp()\"></div>\n" +
40814             "</div>\n" +
40815             "");
40816         }]);
40817
40818         angular.module("uib/template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
40819           $templateCache.put("uib/template/tooltip/tooltip-popup.html",
40820             "<div class=\"tooltip\"\n" +
40821             "  tooltip-animation-class=\"fade\"\n" +
40822             "  uib-tooltip-classes\n" +
40823             "  ng-class=\"{ in: isOpen() }\">\n" +
40824             "  <div class=\"tooltip-arrow\"></div>\n" +
40825             "  <div class=\"tooltip-inner\" ng-bind=\"content\"></div>\n" +
40826             "</div>\n" +
40827             "");
40828         }]);
40829
40830         angular.module("uib/template/tooltip/tooltip-template-popup.html", []).run(["$templateCache", function($templateCache) {
40831           $templateCache.put("uib/template/tooltip/tooltip-template-popup.html",
40832             "<div class=\"tooltip\"\n" +
40833             "  tooltip-animation-class=\"fade\"\n" +
40834             "  uib-tooltip-classes\n" +
40835             "  ng-class=\"{ in: isOpen() }\">\n" +
40836             "  <div class=\"tooltip-arrow\"></div>\n" +
40837             "  <div class=\"tooltip-inner\"\n" +
40838             "    uib-tooltip-template-transclude=\"contentExp()\"\n" +
40839             "    tooltip-template-transclude-scope=\"originScope()\"></div>\n" +
40840             "</div>\n" +
40841             "");
40842         }]);
40843
40844         angular.module("uib/template/popover/popover-html.html", []).run(["$templateCache", function($templateCache) {
40845           $templateCache.put("uib/template/popover/popover-html.html",
40846             "<div class=\"popover\"\n" +
40847             "  tooltip-animation-class=\"fade\"\n" +
40848             "  uib-tooltip-classes\n" +
40849             "  ng-class=\"{ in: isOpen() }\">\n" +
40850             "  <div class=\"arrow\"></div>\n" +
40851             "\n" +
40852             "  <div class=\"popover-inner\">\n" +
40853             "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-if=\"title\"></h3>\n" +
40854             "      <div class=\"popover-content\" ng-bind-html=\"contentExp()\"></div>\n" +
40855             "  </div>\n" +
40856             "</div>\n" +
40857             "");
40858         }]);
40859
40860         angular.module("uib/template/popover/popover-template.html", []).run(["$templateCache", function($templateCache) {
40861           $templateCache.put("uib/template/popover/popover-template.html",
40862             "<div class=\"popover\"\n" +
40863             "  tooltip-animation-class=\"fade\"\n" +
40864             "  uib-tooltip-classes\n" +
40865             "  ng-class=\"{ in: isOpen() }\">\n" +
40866             "  <div class=\"arrow\"></div>\n" +
40867             "\n" +
40868             "  <div class=\"popover-inner\">\n" +
40869             "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-if=\"title\"></h3>\n" +
40870             "      <div class=\"popover-content\"\n" +
40871             "        uib-tooltip-template-transclude=\"contentExp()\"\n" +
40872             "        tooltip-template-transclude-scope=\"originScope()\"></div>\n" +
40873             "  </div>\n" +
40874             "</div>\n" +
40875             "");
40876         }]);
40877
40878         angular.module("uib/template/popover/popover.html", []).run(["$templateCache", function($templateCache) {
40879           $templateCache.put("uib/template/popover/popover.html",
40880             "<div class=\"popover\"\n" +
40881             "  tooltip-animation-class=\"fade\"\n" +
40882             "  uib-tooltip-classes\n" +
40883             "  ng-class=\"{ in: isOpen() }\">\n" +
40884             "  <div class=\"arrow\"></div>\n" +
40885             "\n" +
40886             "  <div class=\"popover-inner\">\n" +
40887             "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-if=\"title\"></h3>\n" +
40888             "      <div class=\"popover-content\" ng-bind=\"content\"></div>\n" +
40889             "  </div>\n" +
40890             "</div>\n" +
40891             "");
40892         }]);
40893
40894         angular.module("uib/template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) {
40895           $templateCache.put("uib/template/progressbar/bar.html",
40896             "<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" +
40897             "");
40898         }]);
40899
40900         angular.module("uib/template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) {
40901           $templateCache.put("uib/template/progressbar/progress.html",
40902             "<div class=\"progress\" ng-transclude aria-labelledby=\"{{::title}}\"></div>");
40903         }]);
40904
40905         angular.module("uib/template/progressbar/progressbar.html", []).run(["$templateCache", function($templateCache) {
40906           $templateCache.put("uib/template/progressbar/progressbar.html",
40907             "<div class=\"progress\">\n" +
40908             "  <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" +
40909             "</div>\n" +
40910             "");
40911         }]);
40912
40913         angular.module("uib/template/rating/rating.html", []).run(["$templateCache", function($templateCache) {
40914           $templateCache.put("uib/template/rating/rating.html",
40915             "<span ng-mouseleave=\"reset()\" ng-keydown=\"onKeydown($event)\" tabindex=\"0\" role=\"slider\" aria-valuemin=\"0\" aria-valuemax=\"{{range.length}}\" aria-valuenow=\"{{value}}\">\n" +
40916             "    <span ng-repeat-start=\"r in range track by $index\" class=\"sr-only\">({{ $index < value ? '*' : ' ' }})</span>\n" +
40917             "    <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" +
40918             "</span>\n" +
40919             "");
40920         }]);
40921
40922         angular.module("uib/template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
40923           $templateCache.put("uib/template/tabs/tab.html",
40924             "<li ng-class=\"{active: active, disabled: disabled}\" class=\"uib-tab\">\n" +
40925             "  <div ng-click=\"select()\" uib-tab-heading-transclude>{{heading}}</div>\n" +
40926             "</li>\n" +
40927             "");
40928         }]);
40929
40930         angular.module("uib/template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
40931           $templateCache.put("uib/template/tabs/tabset.html",
40932             "<div>\n" +
40933             "  <ul class=\"nav nav-{{type || 'tabs'}}\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
40934             "  <div class=\"tab-content\">\n" +
40935             "    <div class=\"tab-pane\" \n" +
40936             "         ng-repeat=\"tab in tabs\" \n" +
40937             "         ng-class=\"{active: tab.active}\"\n" +
40938             "         uib-tab-content-transclude=\"tab\">\n" +
40939             "    </div>\n" +
40940             "  </div>\n" +
40941             "</div>\n" +
40942             "");
40943         }]);
40944
40945         angular.module("uib/template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) {
40946           $templateCache.put("uib/template/timepicker/timepicker.html",
40947             "<table class=\"uib-timepicker\">\n" +
40948             "  <tbody>\n" +
40949             "    <tr class=\"text-center\" ng-show=\"::showSpinners\">\n" +
40950             "      <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" +
40951             "      <td>&nbsp;</td>\n" +
40952             "      <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" +
40953             "      <td ng-show=\"showSeconds\">&nbsp;</td>\n" +
40954             "      <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" +
40955             "      <td ng-show=\"showMeridian\"></td>\n" +
40956             "    </tr>\n" +
40957             "    <tr>\n" +
40958             "      <td class=\"form-group uib-time hours\" ng-class=\"{'has-error': invalidHours}\">\n" +
40959             "        <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" +
40960             "      </td>\n" +
40961             "      <td class=\"uib-separator\">:</td>\n" +
40962             "      <td class=\"form-group uib-time minutes\" ng-class=\"{'has-error': invalidMinutes}\">\n" +
40963             "        <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" +
40964             "      </td>\n" +
40965             "      <td ng-show=\"showSeconds\" class=\"uib-separator\">:</td>\n" +
40966             "      <td class=\"form-group uib-time seconds\" ng-class=\"{'has-error': invalidSeconds}\" ng-show=\"showSeconds\">\n" +
40967             "        <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" +
40968             "      </td>\n" +
40969             "      <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" +
40970             "    </tr>\n" +
40971             "    <tr class=\"text-center\" ng-show=\"::showSpinners\">\n" +
40972             "      <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" +
40973             "      <td>&nbsp;</td>\n" +
40974             "      <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" +
40975             "      <td ng-show=\"showSeconds\">&nbsp;</td>\n" +
40976             "      <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" +
40977             "      <td ng-show=\"showMeridian\"></td>\n" +
40978             "    </tr>\n" +
40979             "  </tbody>\n" +
40980             "</table>\n" +
40981             "");
40982         }]);
40983
40984         angular.module("uib/template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
40985           $templateCache.put("uib/template/typeahead/typeahead-match.html",
40986             "<a href tabindex=\"-1\" ng-bind-html=\"match.label | uibTypeaheadHighlight:query\"></a>\n" +
40987             "");
40988         }]);
40989
40990         angular.module("uib/template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) {
40991           $templateCache.put("uib/template/typeahead/typeahead-popup.html",
40992             "<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" +
40993             "    <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" +
40994             "        <div uib-typeahead-match index=\"$index\" match=\"match\" query=\"query\" template-url=\"templateUrl\"></div>\n" +
40995             "    </li>\n" +
40996             "</ul>\n" +
40997             "");
40998         }]);
40999         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>'); })
41000
41001 /***/ },
41002 /* 8 */
41003 /***/ function(module, exports) {
41004
41005         var app;
41006         (function (app) {
41007             var declares;
41008             (function (declares) {
41009                 var CommandInfo = (function () {
41010                     function CommandInfo(name) {
41011                         this.name = name;
41012                     }
41013                     return CommandInfo;
41014                 })();
41015                 declares.CommandInfo = CommandInfo;
41016             })(declares = app.declares || (app.declares = {}));
41017         })(app || (app = {}));
41018         var app;
41019         (function (app) {
41020             var services;
41021             (function (services) {
41022                 var APIEndPoint = (function () {
41023                     function APIEndPoint($resource, $http) {
41024                         this.$resource = $resource;
41025                         this.$http = $http;
41026                     }
41027                     APIEndPoint.prototype.resource = function (endPoint, data) {
41028                         var customAction = {
41029                             method: 'GET',
41030                             isArray: false
41031                         };
41032                         var execute = {
41033                             method: 'POST',
41034                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
41035                         };
41036                         return this.$resource(endPoint, {}, { execute: execute });
41037                     };
41038                     APIEndPoint.prototype.getOptionControlFile = function (command) {
41039                         var endPoint = '/api/v1/optionControlFile/' + command;
41040                         return this.resource(endPoint, {}).get();
41041                     };
41042                     APIEndPoint.prototype.getFiles = function (fileId) {
41043                         var endPoint = '/api/v1/workspace';
41044                         if (fileId) {
41045                             endPoint += '/' + fileId;
41046                         }
41047                         return this.resource(endPoint, {}).get();
41048                     };
41049                     APIEndPoint.prototype.getDirectories = function () {
41050                         var endPoint = '/api/v1/all/workspace/directory';
41051                         return this.resource(endPoint, {}).get();
41052                     };
41053                     APIEndPoint.prototype.getTags = function () {
41054                         var endPoint = '/api/v1/tagList';
41055                         return this.resource(endPoint, {}).get();
41056                     };
41057                     APIEndPoint.prototype.getCommands = function () {
41058                         var endPoint = '/api/v1/commandList';
41059                         return this.resource(endPoint, {}).get();
41060                     };
41061                     APIEndPoint.prototype.execute = function (data) {
41062                         var endPoint = '/api/v1/execution';
41063                         var fd = new FormData();
41064                         fd.append('data', data);
41065                         return this.$http.post(endPoint, fd, {
41066                             headers: { 'Content-Type': undefined },
41067                             transformRequest: angular.identity
41068                         });
41069                     };
41070                     APIEndPoint.prototype.debug = function () {
41071                         var endPoint = '/api/v1/debug';
41072                         return this.$http.get(endPoint);
41073                     };
41074                     APIEndPoint.prototype.help = function (command) {
41075                         var endPoint = '/api/v1/help/' + command;
41076                         return this.$http.get(endPoint);
41077                     };
41078                     return APIEndPoint;
41079                 })();
41080                 services.APIEndPoint = APIEndPoint;
41081             })(services = app.services || (app.services = {}));
41082         })(app || (app = {}));
41083         var app;
41084         (function (app) {
41085             var services;
41086             (function (services) {
41087                 var MyModal = (function () {
41088                     function MyModal($uibModal) {
41089                         this.$uibModal = $uibModal;
41090                         this.modalOption = {
41091                             backdrop: true,
41092                             controller: null,
41093                             templateUrl: null,
41094                             size: null
41095                         };
41096                     }
41097                     MyModal.prototype.open = function (modalName) {
41098                         if (modalName === 'SelectCommand') {
41099                             this.modalOption.templateUrl = 'templates/select-command.html';
41100                             this.modalOption.size = 'lg';
41101                         }
41102                         return this.$uibModal.open(this.modalOption);
41103                     };
41104                     MyModal.prototype.selectCommand = function () {
41105                         this.modalOption.templateUrl = 'templates/select-command.html';
41106                         this.modalOption.controller = 'selectCommandController';
41107                         this.modalOption.controllerAs = 'c';
41108                         this.modalOption.size = 'lg';
41109                         return this.$uibModal.open(this.modalOption);
41110                     };
41111                     MyModal.prototype.preview = function () {
41112                         this.modalOption.templateUrl = 'templates/preview.html';
41113                         this.modalOption.controller = 'previewController';
41114                         this.modalOption.controllerAs = 'c';
41115                         this.modalOption.size = 'lg';
41116                         return this.$uibModal.open(this.modalOption);
41117                     };
41118                     MyModal.$inject = ['$uibModal'];
41119                     return MyModal;
41120                 })();
41121                 services.MyModal = MyModal;
41122             })(services = app.services || (app.services = {}));
41123         })(app || (app = {}));
41124         var app;
41125         (function (app) {
41126             var services;
41127             (function (services) {
41128                 var WebSocket = (function () {
41129                     function WebSocket($rootScope) {
41130                         this.$rootScope = $rootScope;
41131                         this.socket = io.connect();
41132                     }
41133                     WebSocket.prototype.on = function (eventName, callback) {
41134                         var socket = this.socket;
41135                         var rootScope = this.$rootScope;
41136                         socket.on(eventName, function () {
41137                             var args = arguments;
41138                             rootScope.$apply(function () {
41139                                 callback.apply(socket, args);
41140                             });
41141                         });
41142                     };
41143                     WebSocket.prototype.emit = function (eventName, data, callback) {
41144                         var socket = this.socket;
41145                         var rootScope = this.$rootScope;
41146                         this.socket.emit(eventName, data, function () {
41147                             var args = arguments;
41148                             rootScope.$apply(function () {
41149                                 if (callback)
41150                                     callback.apply(socket, args);
41151                             });
41152                         });
41153                     };
41154                     return WebSocket;
41155                 })();
41156                 services.WebSocket = WebSocket;
41157             })(services = app.services || (app.services = {}));
41158         })(app || (app = {}));
41159         var app;
41160         (function (app) {
41161             var services;
41162             (function (services) {
41163                 var Console = (function () {
41164                     function Console(WebSocket, $rootScope) {
41165                         this.WebSocket = WebSocket;
41166                         this.$rootScope = $rootScope;
41167                         this.WebSocket = WebSocket;
41168                         this.$rootScope = $rootScope;
41169                         this.directiveIDs = [];
41170                         var directiveIDs = this.directiveIDs;
41171                         this.WebSocket.on('console', function (d) {
41172                             var id = d.id;
41173                             var message = d.message;
41174                             if (directiveIDs.indexOf(id) > -1) {
41175                                 $rootScope.$emit(id, message);
41176                             }
41177                         });
41178                     }
41179                     Console.prototype.addDirective = function (id) {
41180                         if (!(this.directiveIDs.indexOf(id) > -1)) {
41181                             this.directiveIDs.push(id);
41182                         }
41183                     };
41184                     Console.prototype.removeDirective = function (id) {
41185                         var i = this.directiveIDs.indexOf(id);
41186                         if (i > -1) {
41187                             this.directiveIDs.splice(i, 1);
41188                         }
41189                     };
41190                     Console.prototype.showIDs = function () {
41191                         console.log(this.directiveIDs);
41192                     };
41193                     return Console;
41194                 })();
41195                 services.Console = Console;
41196             })(services = app.services || (app.services = {}));
41197         })(app || (app = {}));
41198         var app;
41199         (function (app) {
41200             var directives;
41201             (function (directives) {
41202                 var Command = (function () {
41203                     function Command() {
41204                         this.restrict = 'E';
41205                         this.replace = true;
41206                         this.scope = true;
41207                         this.controller = 'commandController';
41208                         this.controllerAs = 'ctrl';
41209                         this.bindToController = {
41210                             index: '=',
41211                             name: '=',
41212                             remove: '&',
41213                             list: '='
41214                         };
41215                         this.templateUrl = 'templates/command.html';
41216                     }
41217                     Command.Factory = function () {
41218                         var directive = function () {
41219                             return new Command();
41220                         };
41221                         directive.$inject = [];
41222                         return directive;
41223                     };
41224                     return Command;
41225                 })();
41226                 directives.Command = Command;
41227                 var CommandController = (function () {
41228                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
41229                         this.APIEndPoint = APIEndPoint;
41230                         this.$scope = $scope;
41231                         this.MyModal = MyModal;
41232                         this.WebSocket = WebSocket;
41233                         this.$window = $window;
41234                         this.$rootScope = $rootScope;
41235                         this.Console = Console;
41236                         var controller = this;
41237                         this.APIEndPoint
41238                             .getOptionControlFile(this.name)
41239                             .$promise
41240                             .then(function (result) {
41241                             controller.options = result.info;
41242                         });
41243                         this.APIEndPoint
41244                             .getDirectories()
41245                             .$promise
41246                             .then(function (result) {
41247                             controller.dirs = result.info;
41248                         });
41249                         this.heading = "[" + this.index + "]: dcdFilePrint";
41250                         this.isOpen = true;
41251                         this.$scope.$on('close', function () {
41252                             controller.isOpen = false;
41253                         });
41254                         function guid() {
41255                             function s4() {
41256                                 return Math.floor((1 + Math.random()) * 0x10000)
41257                                     .toString(16)
41258                                     .substring(1);
41259                             }
41260                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
41261                                 s4() + '-' + s4() + s4() + s4();
41262                         }
41263                         this.uuid = guid();
41264                         this.Console.addDirective(this.uuid);
41265                         this.Console.showIDs();
41266                     }
41267                     CommandController.prototype.submit = function () {
41268                         var opt = [];
41269                         angular.forEach(this.options, function (option) {
41270                             var obj = {
41271                                 name: option.option,
41272                                 arguments: []
41273                             };
41274                             angular.forEach(option.arg, function (arg) {
41275                                 if (arg.input) {
41276                                     if (typeof arg.input === 'object') {
41277                                         obj.arguments.push(arg.input.name);
41278                                     }
41279                                     else {
41280                                         obj.arguments.push(arg.input);
41281                                     }
41282                                 }
41283                             });
41284                             if (obj.arguments.length > 0) {
41285                                 opt.push(obj);
41286                             }
41287                         });
41288                         var execObj = {
41289                             command: this.name,
41290                             workspace: this.workspace.fileId,
41291                             options: opt
41292                         };
41293                         this.APIEndPoint
41294                             .execute(JSON.stringify(execObj))
41295                             .then(function (result) {
41296                             console.log(result);
41297                         });
41298                     };
41299                     CommandController.prototype.removeMySelf = function (index) {
41300                         this.$scope.$destroy();
41301                         this.Console.removeDirective(this.uuid);
41302                         this.remove()(index, this.list);
41303                         this.Console.showIDs();
41304                     };
41305                     CommandController.prototype.reloadFiles = function () {
41306                         var _this = this;
41307                         var fileId = this.workspace.fileId;
41308                         this.APIEndPoint
41309                             .getFiles(fileId)
41310                             .$promise
41311                             .then(function (result) {
41312                             var status = result.status;
41313                             if (status === 'success') {
41314                                 _this.files = result.info;
41315                             }
41316                             else {
41317                                 console.log(result.message);
41318                             }
41319                         });
41320                     };
41321                     CommandController.prototype.debug = function () {
41322                         var div = angular.element(this.$window.document).find("div");
41323                         var consoleTag;
41324                         var parametersTag;
41325                         angular.forEach(div, function (v) {
41326                             if (v.className === "panel-body console") {
41327                                 consoleTag = v;
41328                             }
41329                             else if (v.className === "row parameters-console") {
41330                                 parametersTag = v;
41331                             }
41332                         });
41333                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
41334                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
41335                         consoleTag.style.height = consoleHeight;
41336                         consoleTag.style.width = consoleWidth;
41337                     };
41338                     CommandController.prototype.help = function () {
41339                         this.APIEndPoint
41340                             .help(this.name)
41341                             .then(function (result) {
41342                             console.log(result);
41343                         });
41344                     };
41345                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
41346                     return CommandController;
41347                 })();
41348                 directives.CommandController = CommandController;
41349             })(directives = app.directives || (app.directives = {}));
41350         })(app || (app = {}));
41351         var app;
41352         (function (app) {
41353             var directives;
41354             (function (directives) {
41355                 var HeaderMenu = (function () {
41356                     function HeaderMenu() {
41357                         this.restrict = 'E';
41358                         this.replace = true;
41359                         this.templateUrl = 'templates/header-menu.html';
41360                         this.controller = 'HeaderMenuController';
41361                         this.controllerAs = 'hmc';
41362                         this.scope = true;
41363                     }
41364                     HeaderMenu.Factory = function () {
41365                         var directive = function () {
41366                             return new HeaderMenu();
41367                         };
41368                         return directive;
41369                     };
41370                     return HeaderMenu;
41371                 })();
41372                 directives.HeaderMenu = HeaderMenu;
41373                 var HeaderMenuController = (function () {
41374                     function HeaderMenuController($state) {
41375                         this.$state = $state;
41376                         this.isExecution = this.$state.current.name === 'execution';
41377                         this.isWorkspace = this.$state.current.name === 'workspace';
41378                         this.isHistory = this.$state.current.name === 'history';
41379                     }
41380                     HeaderMenuController.prototype.transit = function (state) {
41381                         this.$state.go(state);
41382                     };
41383                     HeaderMenuController.$inject = ['$state'];
41384                     return HeaderMenuController;
41385                 })();
41386                 directives.HeaderMenuController = HeaderMenuController;
41387             })(directives = app.directives || (app.directives = {}));
41388         })(app || (app = {}));
41389         var app;
41390         (function (app) {
41391             var directives;
41392             (function (directives) {
41393                 var Option = (function () {
41394                     function Option() {
41395                         this.restrict = 'E';
41396                         this.replace = true;
41397                         this.controller = 'optionController';
41398                         this.bindToController = {
41399                             info: '=',
41400                             files: '='
41401                         };
41402                         this.scope = true;
41403                         this.templateUrl = 'templates/option.html';
41404                         this.controllerAs = 'ctrl';
41405                     }
41406                     Option.Factory = function () {
41407                         var directive = function () {
41408                             return new Option();
41409                         };
41410                         directive.$inject = [];
41411                         return directive;
41412                     };
41413                     return Option;
41414                 })();
41415                 directives.Option = Option;
41416                 var OptionController = (function () {
41417                     function OptionController() {
41418                         var controller = this;
41419                         angular.forEach(controller.info.arg, function (arg) {
41420                             if (arg.initialValue) {
41421                                 if (arg.formType === 'number') {
41422                                     arg.input = parseInt(arg.initialValue);
41423                                 }
41424                                 else {
41425                                     arg.input = arg.initialValue;
41426                                 }
41427                             }
41428                         });
41429                     }
41430                     OptionController.$inject = [];
41431                     return OptionController;
41432                 })();
41433                 directives.OptionController = OptionController;
41434             })(directives = app.directives || (app.directives = {}));
41435         })(app || (app = {}));
41436         var app;
41437         (function (app) {
41438             var directives;
41439             (function (directives) {
41440                 var Directory = (function () {
41441                     function Directory() {
41442                         this.restrict = 'E';
41443                         this.replace = true;
41444                         this.controller = 'directoryController';
41445                         this.controllerAs = 'ctrl';
41446                         this.bindToController = {
41447                             info: '=',
41448                             add: '&',
41449                             list: '=',
41450                             files: '='
41451                         };
41452                         this.templateUrl = 'templates/directory.html';
41453                     }
41454                     Directory.Factory = function () {
41455                         var directive = function () {
41456                             return new Directory();
41457                         };
41458                         return directive;
41459                     };
41460                     return Directory;
41461                 })();
41462                 directives.Directory = Directory;
41463                 var DirectoryController = (function () {
41464                     function DirectoryController(APIEndPoint, $scope) {
41465                         this.APIEndPoint = APIEndPoint;
41466                         this.$scope = $scope;
41467                         var controller = this;
41468                         this.APIEndPoint
41469                             .getFiles(this.info.fileId)
41470                             .$promise
41471                             .then(function (result) {
41472                             if (result.status === 'success') {
41473                                 controller.files = result.info;
41474                                 angular.forEach(result.info, function (file) {
41475                                     if (file.fileType === '0') {
41476                                         var o = file;
41477                                         if (controller.info.path === '/') {
41478                                             o.path = '/' + file.name;
41479                                         }
41480                                         else {
41481                                             o.path = controller.info.path + '/' + file.name;
41482                                         }
41483                                         controller.add()(o, controller.list);
41484                                     }
41485                                 });
41486                             }
41487                             ;
41488                         });
41489                     }
41490                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
41491                     return DirectoryController;
41492                 })();
41493                 directives.DirectoryController = DirectoryController;
41494             })(directives = app.directives || (app.directives = {}));
41495         })(app || (app = {}));
41496         var app;
41497         (function (app) {
41498             var controllers;
41499             (function (controllers) {
41500                 var Execution = (function () {
41501                     function Execution(MyModal, $scope) {
41502                         this.MyModal = MyModal;
41503                         this.$scope = $scope;
41504                         this.commandInfoList = [];
41505                     }
41506                     ;
41507                     Execution.prototype.add = function () {
41508                         this.$scope.$broadcast('close');
41509                         var commandInfoList = this.commandInfoList;
41510                         var commandInstance = this.MyModal.selectCommand();
41511                         commandInstance
41512                             .result
41513                             .then(function (command) {
41514                             commandInfoList.push(new app.declares.CommandInfo(command));
41515                         });
41516                     };
41517                     Execution.prototype.open = function () {
41518                         var result = this.MyModal.open('SelectCommand');
41519                         console.log(result);
41520                     };
41521                     Execution.prototype.remove = function (index, list) {
41522                         list.splice(index, 1);
41523                     };
41524                     Execution.prototype.close = function () {
41525                         console.log("close");
41526                     };
41527                     Execution.$inject = ['MyModal', '$scope'];
41528                     return Execution;
41529                 })();
41530                 controllers.Execution = Execution;
41531             })(controllers = app.controllers || (app.controllers = {}));
41532         })(app || (app = {}));
41533         var app;
41534         (function (app) {
41535             var controllers;
41536             (function (controllers) {
41537                 var Workspace = (function () {
41538                     function Workspace($scope, APIEndPoint, MyModal) {
41539                         this.$scope = $scope;
41540                         this.APIEndPoint = APIEndPoint;
41541                         this.MyModal = MyModal;
41542                         this.directoryList = [];
41543                         var controller = this;
41544                         var directoryList = this.directoryList;
41545                         var o = {
41546                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
41547                             name: '',
41548                             parentId: '',
41549                             fileType: '',
41550                             createdAt: '',
41551                             updatedAt: '',
41552                             path: '/'
41553                         };
41554                         directoryList.push(o);
41555                     }
41556                     Workspace.prototype.addDirectory = function (info, directoryList) {
41557                         directoryList.push(info);
41558                     };
41559                     Workspace.prototype.debug = function () {
41560                         this.MyModal.preview();
41561                     };
41562                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
41563                     return Workspace;
41564                 })();
41565                 controllers.Workspace = Workspace;
41566             })(controllers = app.controllers || (app.controllers = {}));
41567         })(app || (app = {}));
41568         var app;
41569         (function (app) {
41570             var controllers;
41571             (function (controllers) {
41572                 var History = (function () {
41573                     function History($scope) {
41574                         this.page = "History";
41575                     }
41576                     History.$inject = ['$scope'];
41577                     return History;
41578                 })();
41579                 controllers.History = History;
41580             })(controllers = app.controllers || (app.controllers = {}));
41581         })(app || (app = {}));
41582         var app;
41583         (function (app) {
41584             var controllers;
41585             (function (controllers) {
41586                 var SelectCommand = (function () {
41587                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
41588                         this.APIEndPoint = APIEndPoint;
41589                         this.$modalInstance = $modalInstance;
41590                         var controller = this;
41591                         this.APIEndPoint
41592                             .getTags()
41593                             .$promise.then(function (result) {
41594                             controller.tags = result.info;
41595                         });
41596                         this.APIEndPoint
41597                             .getCommands()
41598                             .$promise.then(function (result) {
41599                             controller.commands = result.info;
41600                         });
41601                         this.currentTag = 'all';
41602                     }
41603                     SelectCommand.prototype.changeTag = function (tag) {
41604                         this.currentTag = tag;
41605                     };
41606                     SelectCommand.prototype.selectCommand = function (command) {
41607                         this.$modalInstance.close(command);
41608                     };
41609                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
41610                     return SelectCommand;
41611                 })();
41612                 controllers.SelectCommand = SelectCommand;
41613             })(controllers = app.controllers || (app.controllers = {}));
41614         })(app || (app = {}));
41615         var app;
41616         (function (app) {
41617             var controllers;
41618             (function (controllers) {
41619                 var Preview = (function () {
41620                     function Preview($scope, APIEndPoint, $modalInstance) {
41621                         this.APIEndPoint = APIEndPoint;
41622                         this.$modalInstance = $modalInstance;
41623                         var controller = this;
41624                         console.log('preview');
41625                     }
41626                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
41627                     return Preview;
41628                 })();
41629                 controllers.Preview = Preview;
41630             })(controllers = app.controllers || (app.controllers = {}));
41631         })(app || (app = {}));
41632         var filters;
41633         (function (filters) {
41634             function Tag() {
41635                 return function (commands, tag) {
41636                     var result = [];
41637                     angular.forEach(commands, function (command) {
41638                         var flag = false;
41639                         angular.forEach(command.tags, function (value) {
41640                             if (tag === value)
41641                                 flag = true;
41642                         });
41643                         if (flag)
41644                             result.push(command);
41645                     });
41646                     return result;
41647                 };
41648             }
41649             filters.Tag = Tag;
41650         })(filters || (filters = {}));
41651         var app;
41652         (function (app) {
41653             'use strict';
41654             var appName = 'zephyr';
41655             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
41656             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
41657                 $urlRouterProvider.otherwise('/execution');
41658                 $locationProvider.html5Mode({
41659                     enabled: true,
41660                     requireBase: false
41661                 });
41662                 $stateProvider
41663                     .state('execution', {
41664                     url: '/execution',
41665                     templateUrl: 'templates/execution.html',
41666                     controller: 'executionController',
41667                     controllerAs: 'c'
41668                 })
41669                     .state('workspace', {
41670                     url: '/workspace',
41671                     templateUrl: 'templates/workspace.html',
41672                     controller: 'workspaceController',
41673                     controllerAs: 'c'
41674                 })
41675                     .state('history', {
41676                     url: '/history',
41677                     templateUrl: 'templates/history.html',
41678                     controller: 'historyController',
41679                     controllerAs: 'c'
41680                 });
41681             });
41682             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
41683             app.zephyr.service('MyModal', app.services.MyModal);
41684             app.zephyr.service('WebSocket', app.services.WebSocket);
41685             app.zephyr.service('Console', app.services.Console);
41686             app.zephyr.filter('Tag', filters.Tag);
41687             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
41688             app.zephyr.controller('previewController', app.controllers.Preview);
41689             app.zephyr.controller('executionController', app.controllers.Execution);
41690             app.zephyr.controller('workspaceController', app.controllers.Workspace);
41691             app.zephyr.controller('historyController', app.controllers.History);
41692             app.zephyr.controller('commandController', app.directives.CommandController);
41693             app.zephyr.controller('optionController', app.directives.OptionController);
41694             app.zephyr.controller('directoryController', app.directives.DirectoryController);
41695             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
41696             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
41697             app.zephyr.directive('command', app.directives.Command.Factory());
41698             app.zephyr.directive('option', app.directives.Option.Factory());
41699             app.zephyr.directive('directory', app.directives.Directory.Factory());
41700         })(app || (app = {}));
41701
41702
41703 /***/ },
41704 /* 9 */
41705 /***/ function(module, exports) {
41706
41707         var app;
41708         (function (app) {
41709             var declares;
41710             (function (declares) {
41711                 var CommandInfo = (function () {
41712                     function CommandInfo(name) {
41713                         this.name = name;
41714                     }
41715                     return CommandInfo;
41716                 })();
41717                 declares.CommandInfo = CommandInfo;
41718             })(declares = app.declares || (app.declares = {}));
41719         })(app || (app = {}));
41720         var app;
41721         (function (app) {
41722             var services;
41723             (function (services) {
41724                 var APIEndPoint = (function () {
41725                     function APIEndPoint($resource, $http) {
41726                         this.$resource = $resource;
41727                         this.$http = $http;
41728                     }
41729                     APIEndPoint.prototype.resource = function (endPoint, data) {
41730                         var customAction = {
41731                             method: 'GET',
41732                             isArray: false
41733                         };
41734                         var execute = {
41735                             method: 'POST',
41736                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
41737                         };
41738                         return this.$resource(endPoint, {}, { execute: execute });
41739                     };
41740                     APIEndPoint.prototype.getOptionControlFile = function (command) {
41741                         var endPoint = '/api/v1/optionControlFile/' + command;
41742                         return this.resource(endPoint, {}).get();
41743                     };
41744                     APIEndPoint.prototype.getFiles = function (fileId) {
41745                         var endPoint = '/api/v1/workspace';
41746                         if (fileId) {
41747                             endPoint += '/' + fileId;
41748                         }
41749                         return this.resource(endPoint, {}).get();
41750                     };
41751                     APIEndPoint.prototype.getDirectories = function () {
41752                         var endPoint = '/api/v1/all/workspace/directory';
41753                         return this.resource(endPoint, {}).get();
41754                     };
41755                     APIEndPoint.prototype.getTags = function () {
41756                         var endPoint = '/api/v1/tagList';
41757                         return this.resource(endPoint, {}).get();
41758                     };
41759                     APIEndPoint.prototype.getCommands = function () {
41760                         var endPoint = '/api/v1/commandList';
41761                         return this.resource(endPoint, {}).get();
41762                     };
41763                     APIEndPoint.prototype.execute = function (data) {
41764                         var endPoint = '/api/v1/execution';
41765                         var fd = new FormData();
41766                         fd.append('data', data);
41767                         return this.$http.post(endPoint, fd, {
41768                             headers: { 'Content-Type': undefined },
41769                             transformRequest: angular.identity
41770                         });
41771                     };
41772                     APIEndPoint.prototype.debug = function () {
41773                         var endPoint = '/api/v1/debug';
41774                         return this.$http.get(endPoint);
41775                     };
41776                     APIEndPoint.prototype.help = function (command) {
41777                         var endPoint = '/api/v1/help/' + command;
41778                         return this.$http.get(endPoint);
41779                     };
41780                     return APIEndPoint;
41781                 })();
41782                 services.APIEndPoint = APIEndPoint;
41783             })(services = app.services || (app.services = {}));
41784         })(app || (app = {}));
41785         var app;
41786         (function (app) {
41787             var services;
41788             (function (services) {
41789                 var MyModal = (function () {
41790                     function MyModal($uibModal) {
41791                         this.$uibModal = $uibModal;
41792                         this.modalOption = {
41793                             backdrop: true,
41794                             controller: null,
41795                             templateUrl: null,
41796                             size: null
41797                         };
41798                     }
41799                     MyModal.prototype.open = function (modalName) {
41800                         if (modalName === 'SelectCommand') {
41801                             this.modalOption.templateUrl = 'templates/select-command.html';
41802                             this.modalOption.size = 'lg';
41803                         }
41804                         return this.$uibModal.open(this.modalOption);
41805                     };
41806                     MyModal.prototype.selectCommand = function () {
41807                         this.modalOption.templateUrl = 'templates/select-command.html';
41808                         this.modalOption.controller = 'selectCommandController';
41809                         this.modalOption.controllerAs = 'c';
41810                         this.modalOption.size = 'lg';
41811                         return this.$uibModal.open(this.modalOption);
41812                     };
41813                     MyModal.prototype.preview = function () {
41814                         this.modalOption.templateUrl = 'templates/preview.html';
41815                         this.modalOption.controller = 'previewController';
41816                         this.modalOption.controllerAs = 'c';
41817                         this.modalOption.size = 'lg';
41818                         return this.$uibModal.open(this.modalOption);
41819                     };
41820                     MyModal.$inject = ['$uibModal'];
41821                     return MyModal;
41822                 })();
41823                 services.MyModal = MyModal;
41824             })(services = app.services || (app.services = {}));
41825         })(app || (app = {}));
41826         var app;
41827         (function (app) {
41828             var services;
41829             (function (services) {
41830                 var WebSocket = (function () {
41831                     function WebSocket($rootScope) {
41832                         this.$rootScope = $rootScope;
41833                         this.socket = io.connect();
41834                     }
41835                     WebSocket.prototype.on = function (eventName, callback) {
41836                         var socket = this.socket;
41837                         var rootScope = this.$rootScope;
41838                         socket.on(eventName, function () {
41839                             var args = arguments;
41840                             rootScope.$apply(function () {
41841                                 callback.apply(socket, args);
41842                             });
41843                         });
41844                     };
41845                     WebSocket.prototype.emit = function (eventName, data, callback) {
41846                         var socket = this.socket;
41847                         var rootScope = this.$rootScope;
41848                         this.socket.emit(eventName, data, function () {
41849                             var args = arguments;
41850                             rootScope.$apply(function () {
41851                                 if (callback)
41852                                     callback.apply(socket, args);
41853                             });
41854                         });
41855                     };
41856                     return WebSocket;
41857                 })();
41858                 services.WebSocket = WebSocket;
41859             })(services = app.services || (app.services = {}));
41860         })(app || (app = {}));
41861         var app;
41862         (function (app) {
41863             var services;
41864             (function (services) {
41865                 var Console = (function () {
41866                     function Console(WebSocket, $rootScope) {
41867                         this.WebSocket = WebSocket;
41868                         this.$rootScope = $rootScope;
41869                         this.WebSocket = WebSocket;
41870                         this.$rootScope = $rootScope;
41871                         this.directiveIDs = [];
41872                         var directiveIDs = this.directiveIDs;
41873                         this.WebSocket.on('console', function (d) {
41874                             var id = d.id;
41875                             var message = d.message;
41876                             if (directiveIDs.indexOf(id) > -1) {
41877                                 $rootScope.$emit(id, message);
41878                             }
41879                         });
41880                     }
41881                     Console.prototype.addDirective = function (id) {
41882                         if (!(this.directiveIDs.indexOf(id) > -1)) {
41883                             this.directiveIDs.push(id);
41884                         }
41885                     };
41886                     Console.prototype.removeDirective = function (id) {
41887                         var i = this.directiveIDs.indexOf(id);
41888                         if (i > -1) {
41889                             this.directiveIDs.splice(i, 1);
41890                         }
41891                     };
41892                     Console.prototype.showIDs = function () {
41893                         console.log(this.directiveIDs);
41894                     };
41895                     return Console;
41896                 })();
41897                 services.Console = Console;
41898             })(services = app.services || (app.services = {}));
41899         })(app || (app = {}));
41900         var app;
41901         (function (app) {
41902             var directives;
41903             (function (directives) {
41904                 var Command = (function () {
41905                     function Command() {
41906                         this.restrict = 'E';
41907                         this.replace = true;
41908                         this.scope = true;
41909                         this.controller = 'commandController';
41910                         this.controllerAs = 'ctrl';
41911                         this.bindToController = {
41912                             index: '=',
41913                             name: '=',
41914                             remove: '&',
41915                             list: '='
41916                         };
41917                         this.templateUrl = 'templates/command.html';
41918                     }
41919                     Command.Factory = function () {
41920                         var directive = function () {
41921                             return new Command();
41922                         };
41923                         directive.$inject = [];
41924                         return directive;
41925                     };
41926                     return Command;
41927                 })();
41928                 directives.Command = Command;
41929                 var CommandController = (function () {
41930                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
41931                         this.APIEndPoint = APIEndPoint;
41932                         this.$scope = $scope;
41933                         this.MyModal = MyModal;
41934                         this.WebSocket = WebSocket;
41935                         this.$window = $window;
41936                         this.$rootScope = $rootScope;
41937                         this.Console = Console;
41938                         var controller = this;
41939                         this.APIEndPoint
41940                             .getOptionControlFile(this.name)
41941                             .$promise
41942                             .then(function (result) {
41943                             controller.options = result.info;
41944                         });
41945                         this.APIEndPoint
41946                             .getDirectories()
41947                             .$promise
41948                             .then(function (result) {
41949                             controller.dirs = result.info;
41950                         });
41951                         this.heading = "[" + this.index + "]: dcdFilePrint";
41952                         this.isOpen = true;
41953                         this.$scope.$on('close', function () {
41954                             controller.isOpen = false;
41955                         });
41956                         function guid() {
41957                             function s4() {
41958                                 return Math.floor((1 + Math.random()) * 0x10000)
41959                                     .toString(16)
41960                                     .substring(1);
41961                             }
41962                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
41963                                 s4() + '-' + s4() + s4() + s4();
41964                         }
41965                         this.uuid = guid();
41966                         this.Console.addDirective(this.uuid);
41967                         this.Console.showIDs();
41968                     }
41969                     CommandController.prototype.submit = function () {
41970                         var opt = [];
41971                         angular.forEach(this.options, function (option) {
41972                             var obj = {
41973                                 name: option.option,
41974                                 arguments: []
41975                             };
41976                             angular.forEach(option.arg, function (arg) {
41977                                 if (arg.input) {
41978                                     if (typeof arg.input === 'object') {
41979                                         obj.arguments.push(arg.input.name);
41980                                     }
41981                                     else {
41982                                         obj.arguments.push(arg.input);
41983                                     }
41984                                 }
41985                             });
41986                             if (obj.arguments.length > 0) {
41987                                 opt.push(obj);
41988                             }
41989                         });
41990                         var execObj = {
41991                             command: this.name,
41992                             workspace: this.workspace.fileId,
41993                             options: opt
41994                         };
41995                         this.APIEndPoint
41996                             .execute(JSON.stringify(execObj))
41997                             .then(function (result) {
41998                             console.log(result);
41999                         });
42000                     };
42001                     CommandController.prototype.removeMySelf = function (index) {
42002                         this.$scope.$destroy();
42003                         this.Console.removeDirective(this.uuid);
42004                         this.remove()(index, this.list);
42005                         this.Console.showIDs();
42006                     };
42007                     CommandController.prototype.reloadFiles = function () {
42008                         var _this = this;
42009                         var fileId = this.workspace.fileId;
42010                         this.APIEndPoint
42011                             .getFiles(fileId)
42012                             .$promise
42013                             .then(function (result) {
42014                             var status = result.status;
42015                             if (status === 'success') {
42016                                 _this.files = result.info;
42017                             }
42018                             else {
42019                                 console.log(result.message);
42020                             }
42021                         });
42022                     };
42023                     CommandController.prototype.debug = function () {
42024                         var div = angular.element(this.$window.document).find("div");
42025                         var consoleTag;
42026                         var parametersTag;
42027                         angular.forEach(div, function (v) {
42028                             if (v.className === "panel-body console") {
42029                                 consoleTag = v;
42030                             }
42031                             else if (v.className === "row parameters-console") {
42032                                 parametersTag = v;
42033                             }
42034                         });
42035                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
42036                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
42037                         consoleTag.style.height = consoleHeight;
42038                         consoleTag.style.width = consoleWidth;
42039                     };
42040                     CommandController.prototype.help = function () {
42041                         this.APIEndPoint
42042                             .help(this.name)
42043                             .then(function (result) {
42044                             console.log(result);
42045                         });
42046                     };
42047                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
42048                     return CommandController;
42049                 })();
42050                 directives.CommandController = CommandController;
42051             })(directives = app.directives || (app.directives = {}));
42052         })(app || (app = {}));
42053         var app;
42054         (function (app) {
42055             var directives;
42056             (function (directives) {
42057                 var HeaderMenu = (function () {
42058                     function HeaderMenu() {
42059                         this.restrict = 'E';
42060                         this.replace = true;
42061                         this.templateUrl = 'templates/header-menu.html';
42062                         this.controller = 'HeaderMenuController';
42063                         this.controllerAs = 'hmc';
42064                         this.scope = true;
42065                     }
42066                     HeaderMenu.Factory = function () {
42067                         var directive = function () {
42068                             return new HeaderMenu();
42069                         };
42070                         return directive;
42071                     };
42072                     return HeaderMenu;
42073                 })();
42074                 directives.HeaderMenu = HeaderMenu;
42075                 var HeaderMenuController = (function () {
42076                     function HeaderMenuController($state) {
42077                         this.$state = $state;
42078                         this.isExecution = this.$state.current.name === 'execution';
42079                         this.isWorkspace = this.$state.current.name === 'workspace';
42080                         this.isHistory = this.$state.current.name === 'history';
42081                     }
42082                     HeaderMenuController.prototype.transit = function (state) {
42083                         this.$state.go(state);
42084                     };
42085                     HeaderMenuController.$inject = ['$state'];
42086                     return HeaderMenuController;
42087                 })();
42088                 directives.HeaderMenuController = HeaderMenuController;
42089             })(directives = app.directives || (app.directives = {}));
42090         })(app || (app = {}));
42091         var app;
42092         (function (app) {
42093             var directives;
42094             (function (directives) {
42095                 var Option = (function () {
42096                     function Option() {
42097                         this.restrict = 'E';
42098                         this.replace = true;
42099                         this.controller = 'optionController';
42100                         this.bindToController = {
42101                             info: '=',
42102                             files: '='
42103                         };
42104                         this.scope = true;
42105                         this.templateUrl = 'templates/option.html';
42106                         this.controllerAs = 'ctrl';
42107                     }
42108                     Option.Factory = function () {
42109                         var directive = function () {
42110                             return new Option();
42111                         };
42112                         directive.$inject = [];
42113                         return directive;
42114                     };
42115                     return Option;
42116                 })();
42117                 directives.Option = Option;
42118                 var OptionController = (function () {
42119                     function OptionController() {
42120                         var controller = this;
42121                         angular.forEach(controller.info.arg, function (arg) {
42122                             if (arg.initialValue) {
42123                                 if (arg.formType === 'number') {
42124                                     arg.input = parseInt(arg.initialValue);
42125                                 }
42126                                 else {
42127                                     arg.input = arg.initialValue;
42128                                 }
42129                             }
42130                         });
42131                     }
42132                     OptionController.$inject = [];
42133                     return OptionController;
42134                 })();
42135                 directives.OptionController = OptionController;
42136             })(directives = app.directives || (app.directives = {}));
42137         })(app || (app = {}));
42138         var app;
42139         (function (app) {
42140             var directives;
42141             (function (directives) {
42142                 var Directory = (function () {
42143                     function Directory() {
42144                         this.restrict = 'E';
42145                         this.replace = true;
42146                         this.controller = 'directoryController';
42147                         this.controllerAs = 'ctrl';
42148                         this.bindToController = {
42149                             info: '=',
42150                             add: '&',
42151                             list: '=',
42152                             files: '='
42153                         };
42154                         this.templateUrl = 'templates/directory.html';
42155                     }
42156                     Directory.Factory = function () {
42157                         var directive = function () {
42158                             return new Directory();
42159                         };
42160                         return directive;
42161                     };
42162                     return Directory;
42163                 })();
42164                 directives.Directory = Directory;
42165                 var DirectoryController = (function () {
42166                     function DirectoryController(APIEndPoint, $scope) {
42167                         this.APIEndPoint = APIEndPoint;
42168                         this.$scope = $scope;
42169                         var controller = this;
42170                         this.APIEndPoint
42171                             .getFiles(this.info.fileId)
42172                             .$promise
42173                             .then(function (result) {
42174                             if (result.status === 'success') {
42175                                 controller.files = result.info;
42176                                 angular.forEach(result.info, function (file) {
42177                                     if (file.fileType === '0') {
42178                                         var o = file;
42179                                         if (controller.info.path === '/') {
42180                                             o.path = '/' + file.name;
42181                                         }
42182                                         else {
42183                                             o.path = controller.info.path + '/' + file.name;
42184                                         }
42185                                         controller.add()(o, controller.list);
42186                                     }
42187                                 });
42188                             }
42189                             ;
42190                         });
42191                     }
42192                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
42193                     return DirectoryController;
42194                 })();
42195                 directives.DirectoryController = DirectoryController;
42196             })(directives = app.directives || (app.directives = {}));
42197         })(app || (app = {}));
42198         var app;
42199         (function (app) {
42200             var controllers;
42201             (function (controllers) {
42202                 var Execution = (function () {
42203                     function Execution(MyModal, $scope) {
42204                         this.MyModal = MyModal;
42205                         this.$scope = $scope;
42206                         this.commandInfoList = [];
42207                     }
42208                     ;
42209                     Execution.prototype.add = function () {
42210                         this.$scope.$broadcast('close');
42211                         var commandInfoList = this.commandInfoList;
42212                         var commandInstance = this.MyModal.selectCommand();
42213                         commandInstance
42214                             .result
42215                             .then(function (command) {
42216                             commandInfoList.push(new app.declares.CommandInfo(command));
42217                         });
42218                     };
42219                     Execution.prototype.open = function () {
42220                         var result = this.MyModal.open('SelectCommand');
42221                         console.log(result);
42222                     };
42223                     Execution.prototype.remove = function (index, list) {
42224                         list.splice(index, 1);
42225                     };
42226                     Execution.prototype.close = function () {
42227                         console.log("close");
42228                     };
42229                     Execution.$inject = ['MyModal', '$scope'];
42230                     return Execution;
42231                 })();
42232                 controllers.Execution = Execution;
42233             })(controllers = app.controllers || (app.controllers = {}));
42234         })(app || (app = {}));
42235         var app;
42236         (function (app) {
42237             var controllers;
42238             (function (controllers) {
42239                 var Workspace = (function () {
42240                     function Workspace($scope, APIEndPoint, MyModal) {
42241                         this.$scope = $scope;
42242                         this.APIEndPoint = APIEndPoint;
42243                         this.MyModal = MyModal;
42244                         this.directoryList = [];
42245                         var controller = this;
42246                         var directoryList = this.directoryList;
42247                         var o = {
42248                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
42249                             name: '',
42250                             parentId: '',
42251                             fileType: '',
42252                             createdAt: '',
42253                             updatedAt: '',
42254                             path: '/'
42255                         };
42256                         directoryList.push(o);
42257                     }
42258                     Workspace.prototype.addDirectory = function (info, directoryList) {
42259                         directoryList.push(info);
42260                     };
42261                     Workspace.prototype.debug = function () {
42262                         this.MyModal.preview();
42263                     };
42264                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
42265                     return Workspace;
42266                 })();
42267                 controllers.Workspace = Workspace;
42268             })(controllers = app.controllers || (app.controllers = {}));
42269         })(app || (app = {}));
42270         var app;
42271         (function (app) {
42272             var controllers;
42273             (function (controllers) {
42274                 var History = (function () {
42275                     function History($scope) {
42276                         this.page = "History";
42277                     }
42278                     History.$inject = ['$scope'];
42279                     return History;
42280                 })();
42281                 controllers.History = History;
42282             })(controllers = app.controllers || (app.controllers = {}));
42283         })(app || (app = {}));
42284         var app;
42285         (function (app) {
42286             var controllers;
42287             (function (controllers) {
42288                 var SelectCommand = (function () {
42289                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
42290                         this.APIEndPoint = APIEndPoint;
42291                         this.$modalInstance = $modalInstance;
42292                         var controller = this;
42293                         this.APIEndPoint
42294                             .getTags()
42295                             .$promise.then(function (result) {
42296                             controller.tags = result.info;
42297                         });
42298                         this.APIEndPoint
42299                             .getCommands()
42300                             .$promise.then(function (result) {
42301                             controller.commands = result.info;
42302                         });
42303                         this.currentTag = 'all';
42304                     }
42305                     SelectCommand.prototype.changeTag = function (tag) {
42306                         this.currentTag = tag;
42307                     };
42308                     SelectCommand.prototype.selectCommand = function (command) {
42309                         this.$modalInstance.close(command);
42310                     };
42311                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42312                     return SelectCommand;
42313                 })();
42314                 controllers.SelectCommand = SelectCommand;
42315             })(controllers = app.controllers || (app.controllers = {}));
42316         })(app || (app = {}));
42317         var app;
42318         (function (app) {
42319             var controllers;
42320             (function (controllers) {
42321                 var Preview = (function () {
42322                     function Preview($scope, APIEndPoint, $modalInstance) {
42323                         this.APIEndPoint = APIEndPoint;
42324                         this.$modalInstance = $modalInstance;
42325                         var controller = this;
42326                         console.log('preview');
42327                     }
42328                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42329                     return Preview;
42330                 })();
42331                 controllers.Preview = Preview;
42332             })(controllers = app.controllers || (app.controllers = {}));
42333         })(app || (app = {}));
42334         var filters;
42335         (function (filters) {
42336             function Tag() {
42337                 return function (commands, tag) {
42338                     var result = [];
42339                     angular.forEach(commands, function (command) {
42340                         var flag = false;
42341                         angular.forEach(command.tags, function (value) {
42342                             if (tag === value)
42343                                 flag = true;
42344                         });
42345                         if (flag)
42346                             result.push(command);
42347                     });
42348                     return result;
42349                 };
42350             }
42351             filters.Tag = Tag;
42352         })(filters || (filters = {}));
42353         var app;
42354         (function (app) {
42355             'use strict';
42356             var appName = 'zephyr';
42357             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
42358             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
42359                 $urlRouterProvider.otherwise('/execution');
42360                 $locationProvider.html5Mode({
42361                     enabled: true,
42362                     requireBase: false
42363                 });
42364                 $stateProvider
42365                     .state('execution', {
42366                     url: '/execution',
42367                     templateUrl: 'templates/execution.html',
42368                     controller: 'executionController',
42369                     controllerAs: 'c'
42370                 })
42371                     .state('workspace', {
42372                     url: '/workspace',
42373                     templateUrl: 'templates/workspace.html',
42374                     controller: 'workspaceController',
42375                     controllerAs: 'c'
42376                 })
42377                     .state('history', {
42378                     url: '/history',
42379                     templateUrl: 'templates/history.html',
42380                     controller: 'historyController',
42381                     controllerAs: 'c'
42382                 });
42383             });
42384             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
42385             app.zephyr.service('MyModal', app.services.MyModal);
42386             app.zephyr.service('WebSocket', app.services.WebSocket);
42387             app.zephyr.service('Console', app.services.Console);
42388             app.zephyr.filter('Tag', filters.Tag);
42389             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
42390             app.zephyr.controller('previewController', app.controllers.Preview);
42391             app.zephyr.controller('executionController', app.controllers.Execution);
42392             app.zephyr.controller('workspaceController', app.controllers.Workspace);
42393             app.zephyr.controller('historyController', app.controllers.History);
42394             app.zephyr.controller('commandController', app.directives.CommandController);
42395             app.zephyr.controller('optionController', app.directives.OptionController);
42396             app.zephyr.controller('directoryController', app.directives.DirectoryController);
42397             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
42398             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
42399             app.zephyr.directive('command', app.directives.Command.Factory());
42400             app.zephyr.directive('option', app.directives.Option.Factory());
42401             app.zephyr.directive('directory', app.directives.Directory.Factory());
42402         })(app || (app = {}));
42403
42404
42405 /***/ },
42406 /* 10 */
42407 /***/ function(module, exports) {
42408
42409         var app;
42410         (function (app) {
42411             var declares;
42412             (function (declares) {
42413                 var CommandInfo = (function () {
42414                     function CommandInfo(name) {
42415                         this.name = name;
42416                     }
42417                     return CommandInfo;
42418                 })();
42419                 declares.CommandInfo = CommandInfo;
42420             })(declares = app.declares || (app.declares = {}));
42421         })(app || (app = {}));
42422         var app;
42423         (function (app) {
42424             var services;
42425             (function (services) {
42426                 var APIEndPoint = (function () {
42427                     function APIEndPoint($resource, $http) {
42428                         this.$resource = $resource;
42429                         this.$http = $http;
42430                     }
42431                     APIEndPoint.prototype.resource = function (endPoint, data) {
42432                         var customAction = {
42433                             method: 'GET',
42434                             isArray: false
42435                         };
42436                         var execute = {
42437                             method: 'POST',
42438                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
42439                         };
42440                         return this.$resource(endPoint, {}, { execute: execute });
42441                     };
42442                     APIEndPoint.prototype.getOptionControlFile = function (command) {
42443                         var endPoint = '/api/v1/optionControlFile/' + command;
42444                         return this.resource(endPoint, {}).get();
42445                     };
42446                     APIEndPoint.prototype.getFiles = function (fileId) {
42447                         var endPoint = '/api/v1/workspace';
42448                         if (fileId) {
42449                             endPoint += '/' + fileId;
42450                         }
42451                         return this.resource(endPoint, {}).get();
42452                     };
42453                     APIEndPoint.prototype.getDirectories = function () {
42454                         var endPoint = '/api/v1/all/workspace/directory';
42455                         return this.resource(endPoint, {}).get();
42456                     };
42457                     APIEndPoint.prototype.getTags = function () {
42458                         var endPoint = '/api/v1/tagList';
42459                         return this.resource(endPoint, {}).get();
42460                     };
42461                     APIEndPoint.prototype.getCommands = function () {
42462                         var endPoint = '/api/v1/commandList';
42463                         return this.resource(endPoint, {}).get();
42464                     };
42465                     APIEndPoint.prototype.execute = function (data) {
42466                         var endPoint = '/api/v1/execution';
42467                         var fd = new FormData();
42468                         fd.append('data', data);
42469                         return this.$http.post(endPoint, fd, {
42470                             headers: { 'Content-Type': undefined },
42471                             transformRequest: angular.identity
42472                         });
42473                     };
42474                     APIEndPoint.prototype.debug = function () {
42475                         var endPoint = '/api/v1/debug';
42476                         return this.$http.get(endPoint);
42477                     };
42478                     APIEndPoint.prototype.help = function (command) {
42479                         var endPoint = '/api/v1/help/' + command;
42480                         return this.$http.get(endPoint);
42481                     };
42482                     return APIEndPoint;
42483                 })();
42484                 services.APIEndPoint = APIEndPoint;
42485             })(services = app.services || (app.services = {}));
42486         })(app || (app = {}));
42487         var app;
42488         (function (app) {
42489             var services;
42490             (function (services) {
42491                 var MyModal = (function () {
42492                     function MyModal($uibModal) {
42493                         this.$uibModal = $uibModal;
42494                         this.modalOption = {
42495                             backdrop: true,
42496                             controller: null,
42497                             templateUrl: null,
42498                             size: null
42499                         };
42500                     }
42501                     MyModal.prototype.open = function (modalName) {
42502                         if (modalName === 'SelectCommand') {
42503                             this.modalOption.templateUrl = 'templates/select-command.html';
42504                             this.modalOption.size = 'lg';
42505                         }
42506                         return this.$uibModal.open(this.modalOption);
42507                     };
42508                     MyModal.prototype.selectCommand = function () {
42509                         this.modalOption.templateUrl = 'templates/select-command.html';
42510                         this.modalOption.controller = 'selectCommandController';
42511                         this.modalOption.controllerAs = 'c';
42512                         this.modalOption.size = 'lg';
42513                         return this.$uibModal.open(this.modalOption);
42514                     };
42515                     MyModal.prototype.preview = function () {
42516                         this.modalOption.templateUrl = 'templates/preview.html';
42517                         this.modalOption.controller = 'previewController';
42518                         this.modalOption.controllerAs = 'c';
42519                         this.modalOption.size = 'lg';
42520                         return this.$uibModal.open(this.modalOption);
42521                     };
42522                     MyModal.$inject = ['$uibModal'];
42523                     return MyModal;
42524                 })();
42525                 services.MyModal = MyModal;
42526             })(services = app.services || (app.services = {}));
42527         })(app || (app = {}));
42528         var app;
42529         (function (app) {
42530             var services;
42531             (function (services) {
42532                 var WebSocket = (function () {
42533                     function WebSocket($rootScope) {
42534                         this.$rootScope = $rootScope;
42535                         this.socket = io.connect();
42536                     }
42537                     WebSocket.prototype.on = function (eventName, callback) {
42538                         var socket = this.socket;
42539                         var rootScope = this.$rootScope;
42540                         socket.on(eventName, function () {
42541                             var args = arguments;
42542                             rootScope.$apply(function () {
42543                                 callback.apply(socket, args);
42544                             });
42545                         });
42546                     };
42547                     WebSocket.prototype.emit = function (eventName, data, callback) {
42548                         var socket = this.socket;
42549                         var rootScope = this.$rootScope;
42550                         this.socket.emit(eventName, data, function () {
42551                             var args = arguments;
42552                             rootScope.$apply(function () {
42553                                 if (callback)
42554                                     callback.apply(socket, args);
42555                             });
42556                         });
42557                     };
42558                     return WebSocket;
42559                 })();
42560                 services.WebSocket = WebSocket;
42561             })(services = app.services || (app.services = {}));
42562         })(app || (app = {}));
42563         var app;
42564         (function (app) {
42565             var services;
42566             (function (services) {
42567                 var Console = (function () {
42568                     function Console(WebSocket, $rootScope) {
42569                         this.WebSocket = WebSocket;
42570                         this.$rootScope = $rootScope;
42571                         this.WebSocket = WebSocket;
42572                         this.$rootScope = $rootScope;
42573                         this.directiveIDs = [];
42574                         var directiveIDs = this.directiveIDs;
42575                         this.WebSocket.on('console', function (d) {
42576                             var id = d.id;
42577                             var message = d.message;
42578                             if (directiveIDs.indexOf(id) > -1) {
42579                                 $rootScope.$emit(id, message);
42580                             }
42581                         });
42582                     }
42583                     Console.prototype.addDirective = function (id) {
42584                         if (!(this.directiveIDs.indexOf(id) > -1)) {
42585                             this.directiveIDs.push(id);
42586                         }
42587                     };
42588                     Console.prototype.removeDirective = function (id) {
42589                         var i = this.directiveIDs.indexOf(id);
42590                         if (i > -1) {
42591                             this.directiveIDs.splice(i, 1);
42592                         }
42593                     };
42594                     Console.prototype.showIDs = function () {
42595                         console.log(this.directiveIDs);
42596                     };
42597                     return Console;
42598                 })();
42599                 services.Console = Console;
42600             })(services = app.services || (app.services = {}));
42601         })(app || (app = {}));
42602         var app;
42603         (function (app) {
42604             var directives;
42605             (function (directives) {
42606                 var Command = (function () {
42607                     function Command() {
42608                         this.restrict = 'E';
42609                         this.replace = true;
42610                         this.scope = true;
42611                         this.controller = 'commandController';
42612                         this.controllerAs = 'ctrl';
42613                         this.bindToController = {
42614                             index: '=',
42615                             name: '=',
42616                             remove: '&',
42617                             list: '='
42618                         };
42619                         this.templateUrl = 'templates/command.html';
42620                     }
42621                     Command.Factory = function () {
42622                         var directive = function () {
42623                             return new Command();
42624                         };
42625                         directive.$inject = [];
42626                         return directive;
42627                     };
42628                     return Command;
42629                 })();
42630                 directives.Command = Command;
42631                 var CommandController = (function () {
42632                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
42633                         this.APIEndPoint = APIEndPoint;
42634                         this.$scope = $scope;
42635                         this.MyModal = MyModal;
42636                         this.WebSocket = WebSocket;
42637                         this.$window = $window;
42638                         this.$rootScope = $rootScope;
42639                         this.Console = Console;
42640                         var controller = this;
42641                         this.APIEndPoint
42642                             .getOptionControlFile(this.name)
42643                             .$promise
42644                             .then(function (result) {
42645                             controller.options = result.info;
42646                         });
42647                         this.APIEndPoint
42648                             .getDirectories()
42649                             .$promise
42650                             .then(function (result) {
42651                             controller.dirs = result.info;
42652                         });
42653                         this.heading = "[" + this.index + "]: dcdFilePrint";
42654                         this.isOpen = true;
42655                         this.$scope.$on('close', function () {
42656                             controller.isOpen = false;
42657                         });
42658                         function guid() {
42659                             function s4() {
42660                                 return Math.floor((1 + Math.random()) * 0x10000)
42661                                     .toString(16)
42662                                     .substring(1);
42663                             }
42664                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
42665                                 s4() + '-' + s4() + s4() + s4();
42666                         }
42667                         this.uuid = guid();
42668                         this.Console.addDirective(this.uuid);
42669                         this.Console.showIDs();
42670                     }
42671                     CommandController.prototype.submit = function () {
42672                         var opt = [];
42673                         angular.forEach(this.options, function (option) {
42674                             var obj = {
42675                                 name: option.option,
42676                                 arguments: []
42677                             };
42678                             angular.forEach(option.arg, function (arg) {
42679                                 if (arg.input) {
42680                                     if (typeof arg.input === 'object') {
42681                                         obj.arguments.push(arg.input.name);
42682                                     }
42683                                     else {
42684                                         obj.arguments.push(arg.input);
42685                                     }
42686                                 }
42687                             });
42688                             if (obj.arguments.length > 0) {
42689                                 opt.push(obj);
42690                             }
42691                         });
42692                         var execObj = {
42693                             command: this.name,
42694                             workspace: this.workspace.fileId,
42695                             options: opt
42696                         };
42697                         this.APIEndPoint
42698                             .execute(JSON.stringify(execObj))
42699                             .then(function (result) {
42700                             console.log(result);
42701                         });
42702                     };
42703                     CommandController.prototype.removeMySelf = function (index) {
42704                         this.$scope.$destroy();
42705                         this.Console.removeDirective(this.uuid);
42706                         this.remove()(index, this.list);
42707                         this.Console.showIDs();
42708                     };
42709                     CommandController.prototype.reloadFiles = function () {
42710                         var _this = this;
42711                         var fileId = this.workspace.fileId;
42712                         this.APIEndPoint
42713                             .getFiles(fileId)
42714                             .$promise
42715                             .then(function (result) {
42716                             var status = result.status;
42717                             if (status === 'success') {
42718                                 _this.files = result.info;
42719                             }
42720                             else {
42721                                 console.log(result.message);
42722                             }
42723                         });
42724                     };
42725                     CommandController.prototype.debug = function () {
42726                         var div = angular.element(this.$window.document).find("div");
42727                         var consoleTag;
42728                         var parametersTag;
42729                         angular.forEach(div, function (v) {
42730                             if (v.className === "panel-body console") {
42731                                 consoleTag = v;
42732                             }
42733                             else if (v.className === "row parameters-console") {
42734                                 parametersTag = v;
42735                             }
42736                         });
42737                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
42738                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
42739                         consoleTag.style.height = consoleHeight;
42740                         consoleTag.style.width = consoleWidth;
42741                     };
42742                     CommandController.prototype.help = function () {
42743                         this.APIEndPoint
42744                             .help(this.name)
42745                             .then(function (result) {
42746                             console.log(result);
42747                         });
42748                     };
42749                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
42750                     return CommandController;
42751                 })();
42752                 directives.CommandController = CommandController;
42753             })(directives = app.directives || (app.directives = {}));
42754         })(app || (app = {}));
42755         var app;
42756         (function (app) {
42757             var directives;
42758             (function (directives) {
42759                 var HeaderMenu = (function () {
42760                     function HeaderMenu() {
42761                         this.restrict = 'E';
42762                         this.replace = true;
42763                         this.templateUrl = 'templates/header-menu.html';
42764                         this.controller = 'HeaderMenuController';
42765                         this.controllerAs = 'hmc';
42766                         this.scope = true;
42767                     }
42768                     HeaderMenu.Factory = function () {
42769                         var directive = function () {
42770                             return new HeaderMenu();
42771                         };
42772                         return directive;
42773                     };
42774                     return HeaderMenu;
42775                 })();
42776                 directives.HeaderMenu = HeaderMenu;
42777                 var HeaderMenuController = (function () {
42778                     function HeaderMenuController($state) {
42779                         this.$state = $state;
42780                         this.isExecution = this.$state.current.name === 'execution';
42781                         this.isWorkspace = this.$state.current.name === 'workspace';
42782                         this.isHistory = this.$state.current.name === 'history';
42783                     }
42784                     HeaderMenuController.prototype.transit = function (state) {
42785                         this.$state.go(state);
42786                     };
42787                     HeaderMenuController.$inject = ['$state'];
42788                     return HeaderMenuController;
42789                 })();
42790                 directives.HeaderMenuController = HeaderMenuController;
42791             })(directives = app.directives || (app.directives = {}));
42792         })(app || (app = {}));
42793         var app;
42794         (function (app) {
42795             var directives;
42796             (function (directives) {
42797                 var Option = (function () {
42798                     function Option() {
42799                         this.restrict = 'E';
42800                         this.replace = true;
42801                         this.controller = 'optionController';
42802                         this.bindToController = {
42803                             info: '=',
42804                             files: '='
42805                         };
42806                         this.scope = true;
42807                         this.templateUrl = 'templates/option.html';
42808                         this.controllerAs = 'ctrl';
42809                     }
42810                     Option.Factory = function () {
42811                         var directive = function () {
42812                             return new Option();
42813                         };
42814                         directive.$inject = [];
42815                         return directive;
42816                     };
42817                     return Option;
42818                 })();
42819                 directives.Option = Option;
42820                 var OptionController = (function () {
42821                     function OptionController() {
42822                         var controller = this;
42823                         angular.forEach(controller.info.arg, function (arg) {
42824                             if (arg.initialValue) {
42825                                 if (arg.formType === 'number') {
42826                                     arg.input = parseInt(arg.initialValue);
42827                                 }
42828                                 else {
42829                                     arg.input = arg.initialValue;
42830                                 }
42831                             }
42832                         });
42833                     }
42834                     OptionController.$inject = [];
42835                     return OptionController;
42836                 })();
42837                 directives.OptionController = OptionController;
42838             })(directives = app.directives || (app.directives = {}));
42839         })(app || (app = {}));
42840         var app;
42841         (function (app) {
42842             var directives;
42843             (function (directives) {
42844                 var Directory = (function () {
42845                     function Directory() {
42846                         this.restrict = 'E';
42847                         this.replace = true;
42848                         this.controller = 'directoryController';
42849                         this.controllerAs = 'ctrl';
42850                         this.bindToController = {
42851                             info: '=',
42852                             add: '&',
42853                             list: '=',
42854                             files: '='
42855                         };
42856                         this.templateUrl = 'templates/directory.html';
42857                     }
42858                     Directory.Factory = function () {
42859                         var directive = function () {
42860                             return new Directory();
42861                         };
42862                         return directive;
42863                     };
42864                     return Directory;
42865                 })();
42866                 directives.Directory = Directory;
42867                 var DirectoryController = (function () {
42868                     function DirectoryController(APIEndPoint, $scope) {
42869                         this.APIEndPoint = APIEndPoint;
42870                         this.$scope = $scope;
42871                         var controller = this;
42872                         this.APIEndPoint
42873                             .getFiles(this.info.fileId)
42874                             .$promise
42875                             .then(function (result) {
42876                             if (result.status === 'success') {
42877                                 controller.files = result.info;
42878                                 angular.forEach(result.info, function (file) {
42879                                     if (file.fileType === '0') {
42880                                         var o = file;
42881                                         if (controller.info.path === '/') {
42882                                             o.path = '/' + file.name;
42883                                         }
42884                                         else {
42885                                             o.path = controller.info.path + '/' + file.name;
42886                                         }
42887                                         controller.add()(o, controller.list);
42888                                     }
42889                                 });
42890                             }
42891                             ;
42892                         });
42893                     }
42894                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
42895                     return DirectoryController;
42896                 })();
42897                 directives.DirectoryController = DirectoryController;
42898             })(directives = app.directives || (app.directives = {}));
42899         })(app || (app = {}));
42900         var app;
42901         (function (app) {
42902             var controllers;
42903             (function (controllers) {
42904                 var Execution = (function () {
42905                     function Execution(MyModal, $scope) {
42906                         this.MyModal = MyModal;
42907                         this.$scope = $scope;
42908                         this.commandInfoList = [];
42909                     }
42910                     ;
42911                     Execution.prototype.add = function () {
42912                         this.$scope.$broadcast('close');
42913                         var commandInfoList = this.commandInfoList;
42914                         var commandInstance = this.MyModal.selectCommand();
42915                         commandInstance
42916                             .result
42917                             .then(function (command) {
42918                             commandInfoList.push(new app.declares.CommandInfo(command));
42919                         });
42920                     };
42921                     Execution.prototype.open = function () {
42922                         var result = this.MyModal.open('SelectCommand');
42923                         console.log(result);
42924                     };
42925                     Execution.prototype.remove = function (index, list) {
42926                         list.splice(index, 1);
42927                     };
42928                     Execution.prototype.close = function () {
42929                         console.log("close");
42930                     };
42931                     Execution.$inject = ['MyModal', '$scope'];
42932                     return Execution;
42933                 })();
42934                 controllers.Execution = Execution;
42935             })(controllers = app.controllers || (app.controllers = {}));
42936         })(app || (app = {}));
42937         var app;
42938         (function (app) {
42939             var controllers;
42940             (function (controllers) {
42941                 var Workspace = (function () {
42942                     function Workspace($scope, APIEndPoint, MyModal) {
42943                         this.$scope = $scope;
42944                         this.APIEndPoint = APIEndPoint;
42945                         this.MyModal = MyModal;
42946                         this.directoryList = [];
42947                         var controller = this;
42948                         var directoryList = this.directoryList;
42949                         var o = {
42950                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
42951                             name: '',
42952                             parentId: '',
42953                             fileType: '',
42954                             createdAt: '',
42955                             updatedAt: '',
42956                             path: '/'
42957                         };
42958                         directoryList.push(o);
42959                     }
42960                     Workspace.prototype.addDirectory = function (info, directoryList) {
42961                         directoryList.push(info);
42962                     };
42963                     Workspace.prototype.debug = function () {
42964                         this.MyModal.preview();
42965                     };
42966                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
42967                     return Workspace;
42968                 })();
42969                 controllers.Workspace = Workspace;
42970             })(controllers = app.controllers || (app.controllers = {}));
42971         })(app || (app = {}));
42972         var app;
42973         (function (app) {
42974             var controllers;
42975             (function (controllers) {
42976                 var History = (function () {
42977                     function History($scope) {
42978                         this.page = "History";
42979                     }
42980                     History.$inject = ['$scope'];
42981                     return History;
42982                 })();
42983                 controllers.History = History;
42984             })(controllers = app.controllers || (app.controllers = {}));
42985         })(app || (app = {}));
42986         var app;
42987         (function (app) {
42988             var controllers;
42989             (function (controllers) {
42990                 var SelectCommand = (function () {
42991                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
42992                         this.APIEndPoint = APIEndPoint;
42993                         this.$modalInstance = $modalInstance;
42994                         var controller = this;
42995                         this.APIEndPoint
42996                             .getTags()
42997                             .$promise.then(function (result) {
42998                             controller.tags = result.info;
42999                         });
43000                         this.APIEndPoint
43001                             .getCommands()
43002                             .$promise.then(function (result) {
43003                             controller.commands = result.info;
43004                         });
43005                         this.currentTag = 'all';
43006                     }
43007                     SelectCommand.prototype.changeTag = function (tag) {
43008                         this.currentTag = tag;
43009                     };
43010                     SelectCommand.prototype.selectCommand = function (command) {
43011                         this.$modalInstance.close(command);
43012                     };
43013                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43014                     return SelectCommand;
43015                 })();
43016                 controllers.SelectCommand = SelectCommand;
43017             })(controllers = app.controllers || (app.controllers = {}));
43018         })(app || (app = {}));
43019         var app;
43020         (function (app) {
43021             var controllers;
43022             (function (controllers) {
43023                 var Preview = (function () {
43024                     function Preview($scope, APIEndPoint, $modalInstance) {
43025                         this.APIEndPoint = APIEndPoint;
43026                         this.$modalInstance = $modalInstance;
43027                         var controller = this;
43028                         console.log('preview');
43029                     }
43030                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43031                     return Preview;
43032                 })();
43033                 controllers.Preview = Preview;
43034             })(controllers = app.controllers || (app.controllers = {}));
43035         })(app || (app = {}));
43036         var filters;
43037         (function (filters) {
43038             function Tag() {
43039                 return function (commands, tag) {
43040                     var result = [];
43041                     angular.forEach(commands, function (command) {
43042                         var flag = false;
43043                         angular.forEach(command.tags, function (value) {
43044                             if (tag === value)
43045                                 flag = true;
43046                         });
43047                         if (flag)
43048                             result.push(command);
43049                     });
43050                     return result;
43051                 };
43052             }
43053             filters.Tag = Tag;
43054         })(filters || (filters = {}));
43055         var app;
43056         (function (app) {
43057             'use strict';
43058             var appName = 'zephyr';
43059             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
43060             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
43061                 $urlRouterProvider.otherwise('/execution');
43062                 $locationProvider.html5Mode({
43063                     enabled: true,
43064                     requireBase: false
43065                 });
43066                 $stateProvider
43067                     .state('execution', {
43068                     url: '/execution',
43069                     templateUrl: 'templates/execution.html',
43070                     controller: 'executionController',
43071                     controllerAs: 'c'
43072                 })
43073                     .state('workspace', {
43074                     url: '/workspace',
43075                     templateUrl: 'templates/workspace.html',
43076                     controller: 'workspaceController',
43077                     controllerAs: 'c'
43078                 })
43079                     .state('history', {
43080                     url: '/history',
43081                     templateUrl: 'templates/history.html',
43082                     controller: 'historyController',
43083                     controllerAs: 'c'
43084                 });
43085             });
43086             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
43087             app.zephyr.service('MyModal', app.services.MyModal);
43088             app.zephyr.service('WebSocket', app.services.WebSocket);
43089             app.zephyr.service('Console', app.services.Console);
43090             app.zephyr.filter('Tag', filters.Tag);
43091             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
43092             app.zephyr.controller('previewController', app.controllers.Preview);
43093             app.zephyr.controller('executionController', app.controllers.Execution);
43094             app.zephyr.controller('workspaceController', app.controllers.Workspace);
43095             app.zephyr.controller('historyController', app.controllers.History);
43096             app.zephyr.controller('commandController', app.directives.CommandController);
43097             app.zephyr.controller('optionController', app.directives.OptionController);
43098             app.zephyr.controller('directoryController', app.directives.DirectoryController);
43099             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
43100             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
43101             app.zephyr.directive('command', app.directives.Command.Factory());
43102             app.zephyr.directive('option', app.directives.Option.Factory());
43103             app.zephyr.directive('directory', app.directives.Directory.Factory());
43104         })(app || (app = {}));
43105
43106
43107 /***/ },
43108 /* 11 */
43109 /***/ function(module, exports) {
43110
43111         var app;
43112         (function (app) {
43113             var declares;
43114             (function (declares) {
43115                 var CommandInfo = (function () {
43116                     function CommandInfo(name) {
43117                         this.name = name;
43118                     }
43119                     return CommandInfo;
43120                 })();
43121                 declares.CommandInfo = CommandInfo;
43122             })(declares = app.declares || (app.declares = {}));
43123         })(app || (app = {}));
43124         var app;
43125         (function (app) {
43126             var services;
43127             (function (services) {
43128                 var APIEndPoint = (function () {
43129                     function APIEndPoint($resource, $http) {
43130                         this.$resource = $resource;
43131                         this.$http = $http;
43132                     }
43133                     APIEndPoint.prototype.resource = function (endPoint, data) {
43134                         var customAction = {
43135                             method: 'GET',
43136                             isArray: false
43137                         };
43138                         var execute = {
43139                             method: 'POST',
43140                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
43141                         };
43142                         return this.$resource(endPoint, {}, { execute: execute });
43143                     };
43144                     APIEndPoint.prototype.getOptionControlFile = function (command) {
43145                         var endPoint = '/api/v1/optionControlFile/' + command;
43146                         return this.resource(endPoint, {}).get();
43147                     };
43148                     APIEndPoint.prototype.getFiles = function (fileId) {
43149                         var endPoint = '/api/v1/workspace';
43150                         if (fileId) {
43151                             endPoint += '/' + fileId;
43152                         }
43153                         return this.resource(endPoint, {}).get();
43154                     };
43155                     APIEndPoint.prototype.getDirectories = function () {
43156                         var endPoint = '/api/v1/all/workspace/directory';
43157                         return this.resource(endPoint, {}).get();
43158                     };
43159                     APIEndPoint.prototype.getTags = function () {
43160                         var endPoint = '/api/v1/tagList';
43161                         return this.resource(endPoint, {}).get();
43162                     };
43163                     APIEndPoint.prototype.getCommands = function () {
43164                         var endPoint = '/api/v1/commandList';
43165                         return this.resource(endPoint, {}).get();
43166                     };
43167                     APIEndPoint.prototype.execute = function (data) {
43168                         var endPoint = '/api/v1/execution';
43169                         var fd = new FormData();
43170                         fd.append('data', data);
43171                         return this.$http.post(endPoint, fd, {
43172                             headers: { 'Content-Type': undefined },
43173                             transformRequest: angular.identity
43174                         });
43175                     };
43176                     APIEndPoint.prototype.debug = function () {
43177                         var endPoint = '/api/v1/debug';
43178                         return this.$http.get(endPoint);
43179                     };
43180                     APIEndPoint.prototype.help = function (command) {
43181                         var endPoint = '/api/v1/help/' + command;
43182                         return this.$http.get(endPoint);
43183                     };
43184                     return APIEndPoint;
43185                 })();
43186                 services.APIEndPoint = APIEndPoint;
43187             })(services = app.services || (app.services = {}));
43188         })(app || (app = {}));
43189         var app;
43190         (function (app) {
43191             var services;
43192             (function (services) {
43193                 var MyModal = (function () {
43194                     function MyModal($uibModal) {
43195                         this.$uibModal = $uibModal;
43196                         this.modalOption = {
43197                             backdrop: true,
43198                             controller: null,
43199                             templateUrl: null,
43200                             size: null
43201                         };
43202                     }
43203                     MyModal.prototype.open = function (modalName) {
43204                         if (modalName === 'SelectCommand') {
43205                             this.modalOption.templateUrl = 'templates/select-command.html';
43206                             this.modalOption.size = 'lg';
43207                         }
43208                         return this.$uibModal.open(this.modalOption);
43209                     };
43210                     MyModal.prototype.selectCommand = function () {
43211                         this.modalOption.templateUrl = 'templates/select-command.html';
43212                         this.modalOption.controller = 'selectCommandController';
43213                         this.modalOption.controllerAs = 'c';
43214                         this.modalOption.size = 'lg';
43215                         return this.$uibModal.open(this.modalOption);
43216                     };
43217                     MyModal.prototype.preview = function () {
43218                         this.modalOption.templateUrl = 'templates/preview.html';
43219                         this.modalOption.controller = 'previewController';
43220                         this.modalOption.controllerAs = 'c';
43221                         this.modalOption.size = 'lg';
43222                         return this.$uibModal.open(this.modalOption);
43223                     };
43224                     MyModal.$inject = ['$uibModal'];
43225                     return MyModal;
43226                 })();
43227                 services.MyModal = MyModal;
43228             })(services = app.services || (app.services = {}));
43229         })(app || (app = {}));
43230         var app;
43231         (function (app) {
43232             var services;
43233             (function (services) {
43234                 var WebSocket = (function () {
43235                     function WebSocket($rootScope) {
43236                         this.$rootScope = $rootScope;
43237                         this.socket = io.connect();
43238                     }
43239                     WebSocket.prototype.on = function (eventName, callback) {
43240                         var socket = this.socket;
43241                         var rootScope = this.$rootScope;
43242                         socket.on(eventName, function () {
43243                             var args = arguments;
43244                             rootScope.$apply(function () {
43245                                 callback.apply(socket, args);
43246                             });
43247                         });
43248                     };
43249                     WebSocket.prototype.emit = function (eventName, data, callback) {
43250                         var socket = this.socket;
43251                         var rootScope = this.$rootScope;
43252                         this.socket.emit(eventName, data, function () {
43253                             var args = arguments;
43254                             rootScope.$apply(function () {
43255                                 if (callback)
43256                                     callback.apply(socket, args);
43257                             });
43258                         });
43259                     };
43260                     return WebSocket;
43261                 })();
43262                 services.WebSocket = WebSocket;
43263             })(services = app.services || (app.services = {}));
43264         })(app || (app = {}));
43265         var app;
43266         (function (app) {
43267             var services;
43268             (function (services) {
43269                 var Console = (function () {
43270                     function Console(WebSocket, $rootScope) {
43271                         this.WebSocket = WebSocket;
43272                         this.$rootScope = $rootScope;
43273                         this.WebSocket = WebSocket;
43274                         this.$rootScope = $rootScope;
43275                         this.directiveIDs = [];
43276                         var directiveIDs = this.directiveIDs;
43277                         this.WebSocket.on('console', function (d) {
43278                             var id = d.id;
43279                             var message = d.message;
43280                             if (directiveIDs.indexOf(id) > -1) {
43281                                 $rootScope.$emit(id, message);
43282                             }
43283                         });
43284                     }
43285                     Console.prototype.addDirective = function (id) {
43286                         if (!(this.directiveIDs.indexOf(id) > -1)) {
43287                             this.directiveIDs.push(id);
43288                         }
43289                     };
43290                     Console.prototype.removeDirective = function (id) {
43291                         var i = this.directiveIDs.indexOf(id);
43292                         if (i > -1) {
43293                             this.directiveIDs.splice(i, 1);
43294                         }
43295                     };
43296                     Console.prototype.showIDs = function () {
43297                         console.log(this.directiveIDs);
43298                     };
43299                     return Console;
43300                 })();
43301                 services.Console = Console;
43302             })(services = app.services || (app.services = {}));
43303         })(app || (app = {}));
43304         var app;
43305         (function (app) {
43306             var directives;
43307             (function (directives) {
43308                 var Command = (function () {
43309                     function Command() {
43310                         this.restrict = 'E';
43311                         this.replace = true;
43312                         this.scope = true;
43313                         this.controller = 'commandController';
43314                         this.controllerAs = 'ctrl';
43315                         this.bindToController = {
43316                             index: '=',
43317                             name: '=',
43318                             remove: '&',
43319                             list: '='
43320                         };
43321                         this.templateUrl = 'templates/command.html';
43322                     }
43323                     Command.Factory = function () {
43324                         var directive = function () {
43325                             return new Command();
43326                         };
43327                         directive.$inject = [];
43328                         return directive;
43329                     };
43330                     return Command;
43331                 })();
43332                 directives.Command = Command;
43333                 var CommandController = (function () {
43334                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
43335                         this.APIEndPoint = APIEndPoint;
43336                         this.$scope = $scope;
43337                         this.MyModal = MyModal;
43338                         this.WebSocket = WebSocket;
43339                         this.$window = $window;
43340                         this.$rootScope = $rootScope;
43341                         this.Console = Console;
43342                         var controller = this;
43343                         this.APIEndPoint
43344                             .getOptionControlFile(this.name)
43345                             .$promise
43346                             .then(function (result) {
43347                             controller.options = result.info;
43348                         });
43349                         this.APIEndPoint
43350                             .getDirectories()
43351                             .$promise
43352                             .then(function (result) {
43353                             controller.dirs = result.info;
43354                         });
43355                         this.heading = "[" + this.index + "]: dcdFilePrint";
43356                         this.isOpen = true;
43357                         this.$scope.$on('close', function () {
43358                             controller.isOpen = false;
43359                         });
43360                         function guid() {
43361                             function s4() {
43362                                 return Math.floor((1 + Math.random()) * 0x10000)
43363                                     .toString(16)
43364                                     .substring(1);
43365                             }
43366                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
43367                                 s4() + '-' + s4() + s4() + s4();
43368                         }
43369                         this.uuid = guid();
43370                         this.Console.addDirective(this.uuid);
43371                         this.Console.showIDs();
43372                     }
43373                     CommandController.prototype.submit = function () {
43374                         var opt = [];
43375                         angular.forEach(this.options, function (option) {
43376                             var obj = {
43377                                 name: option.option,
43378                                 arguments: []
43379                             };
43380                             angular.forEach(option.arg, function (arg) {
43381                                 if (arg.input) {
43382                                     if (typeof arg.input === 'object') {
43383                                         obj.arguments.push(arg.input.name);
43384                                     }
43385                                     else {
43386                                         obj.arguments.push(arg.input);
43387                                     }
43388                                 }
43389                             });
43390                             if (obj.arguments.length > 0) {
43391                                 opt.push(obj);
43392                             }
43393                         });
43394                         var execObj = {
43395                             command: this.name,
43396                             workspace: this.workspace.fileId,
43397                             options: opt
43398                         };
43399                         this.APIEndPoint
43400                             .execute(JSON.stringify(execObj))
43401                             .then(function (result) {
43402                             console.log(result);
43403                         });
43404                     };
43405                     CommandController.prototype.removeMySelf = function (index) {
43406                         this.$scope.$destroy();
43407                         this.Console.removeDirective(this.uuid);
43408                         this.remove()(index, this.list);
43409                         this.Console.showIDs();
43410                     };
43411                     CommandController.prototype.reloadFiles = function () {
43412                         var _this = this;
43413                         var fileId = this.workspace.fileId;
43414                         this.APIEndPoint
43415                             .getFiles(fileId)
43416                             .$promise
43417                             .then(function (result) {
43418                             var status = result.status;
43419                             if (status === 'success') {
43420                                 _this.files = result.info;
43421                             }
43422                             else {
43423                                 console.log(result.message);
43424                             }
43425                         });
43426                     };
43427                     CommandController.prototype.debug = function () {
43428                         var div = angular.element(this.$window.document).find("div");
43429                         var consoleTag;
43430                         var parametersTag;
43431                         angular.forEach(div, function (v) {
43432                             if (v.className === "panel-body console") {
43433                                 consoleTag = v;
43434                             }
43435                             else if (v.className === "row parameters-console") {
43436                                 parametersTag = v;
43437                             }
43438                         });
43439                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
43440                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
43441                         consoleTag.style.height = consoleHeight;
43442                         consoleTag.style.width = consoleWidth;
43443                     };
43444                     CommandController.prototype.help = function () {
43445                         this.APIEndPoint
43446                             .help(this.name)
43447                             .then(function (result) {
43448                             console.log(result);
43449                         });
43450                     };
43451                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
43452                     return CommandController;
43453                 })();
43454                 directives.CommandController = CommandController;
43455             })(directives = app.directives || (app.directives = {}));
43456         })(app || (app = {}));
43457         var app;
43458         (function (app) {
43459             var directives;
43460             (function (directives) {
43461                 var HeaderMenu = (function () {
43462                     function HeaderMenu() {
43463                         this.restrict = 'E';
43464                         this.replace = true;
43465                         this.templateUrl = 'templates/header-menu.html';
43466                         this.controller = 'HeaderMenuController';
43467                         this.controllerAs = 'hmc';
43468                         this.scope = true;
43469                     }
43470                     HeaderMenu.Factory = function () {
43471                         var directive = function () {
43472                             return new HeaderMenu();
43473                         };
43474                         return directive;
43475                     };
43476                     return HeaderMenu;
43477                 })();
43478                 directives.HeaderMenu = HeaderMenu;
43479                 var HeaderMenuController = (function () {
43480                     function HeaderMenuController($state) {
43481                         this.$state = $state;
43482                         this.isExecution = this.$state.current.name === 'execution';
43483                         this.isWorkspace = this.$state.current.name === 'workspace';
43484                         this.isHistory = this.$state.current.name === 'history';
43485                     }
43486                     HeaderMenuController.prototype.transit = function (state) {
43487                         this.$state.go(state);
43488                     };
43489                     HeaderMenuController.$inject = ['$state'];
43490                     return HeaderMenuController;
43491                 })();
43492                 directives.HeaderMenuController = HeaderMenuController;
43493             })(directives = app.directives || (app.directives = {}));
43494         })(app || (app = {}));
43495         var app;
43496         (function (app) {
43497             var directives;
43498             (function (directives) {
43499                 var Option = (function () {
43500                     function Option() {
43501                         this.restrict = 'E';
43502                         this.replace = true;
43503                         this.controller = 'optionController';
43504                         this.bindToController = {
43505                             info: '=',
43506                             files: '='
43507                         };
43508                         this.scope = true;
43509                         this.templateUrl = 'templates/option.html';
43510                         this.controllerAs = 'ctrl';
43511                     }
43512                     Option.Factory = function () {
43513                         var directive = function () {
43514                             return new Option();
43515                         };
43516                         directive.$inject = [];
43517                         return directive;
43518                     };
43519                     return Option;
43520                 })();
43521                 directives.Option = Option;
43522                 var OptionController = (function () {
43523                     function OptionController() {
43524                         var controller = this;
43525                         angular.forEach(controller.info.arg, function (arg) {
43526                             if (arg.initialValue) {
43527                                 if (arg.formType === 'number') {
43528                                     arg.input = parseInt(arg.initialValue);
43529                                 }
43530                                 else {
43531                                     arg.input = arg.initialValue;
43532                                 }
43533                             }
43534                         });
43535                     }
43536                     OptionController.$inject = [];
43537                     return OptionController;
43538                 })();
43539                 directives.OptionController = OptionController;
43540             })(directives = app.directives || (app.directives = {}));
43541         })(app || (app = {}));
43542         var app;
43543         (function (app) {
43544             var directives;
43545             (function (directives) {
43546                 var Directory = (function () {
43547                     function Directory() {
43548                         this.restrict = 'E';
43549                         this.replace = true;
43550                         this.controller = 'directoryController';
43551                         this.controllerAs = 'ctrl';
43552                         this.bindToController = {
43553                             info: '=',
43554                             add: '&',
43555                             list: '=',
43556                             files: '='
43557                         };
43558                         this.templateUrl = 'templates/directory.html';
43559                     }
43560                     Directory.Factory = function () {
43561                         var directive = function () {
43562                             return new Directory();
43563                         };
43564                         return directive;
43565                     };
43566                     return Directory;
43567                 })();
43568                 directives.Directory = Directory;
43569                 var DirectoryController = (function () {
43570                     function DirectoryController(APIEndPoint, $scope) {
43571                         this.APIEndPoint = APIEndPoint;
43572                         this.$scope = $scope;
43573                         var controller = this;
43574                         this.APIEndPoint
43575                             .getFiles(this.info.fileId)
43576                             .$promise
43577                             .then(function (result) {
43578                             if (result.status === 'success') {
43579                                 controller.files = result.info;
43580                                 angular.forEach(result.info, function (file) {
43581                                     if (file.fileType === '0') {
43582                                         var o = file;
43583                                         if (controller.info.path === '/') {
43584                                             o.path = '/' + file.name;
43585                                         }
43586                                         else {
43587                                             o.path = controller.info.path + '/' + file.name;
43588                                         }
43589                                         controller.add()(o, controller.list);
43590                                     }
43591                                 });
43592                             }
43593                             ;
43594                         });
43595                     }
43596                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
43597                     return DirectoryController;
43598                 })();
43599                 directives.DirectoryController = DirectoryController;
43600             })(directives = app.directives || (app.directives = {}));
43601         })(app || (app = {}));
43602         var app;
43603         (function (app) {
43604             var controllers;
43605             (function (controllers) {
43606                 var Execution = (function () {
43607                     function Execution(MyModal, $scope) {
43608                         this.MyModal = MyModal;
43609                         this.$scope = $scope;
43610                         this.commandInfoList = [];
43611                     }
43612                     ;
43613                     Execution.prototype.add = function () {
43614                         this.$scope.$broadcast('close');
43615                         var commandInfoList = this.commandInfoList;
43616                         var commandInstance = this.MyModal.selectCommand();
43617                         commandInstance
43618                             .result
43619                             .then(function (command) {
43620                             commandInfoList.push(new app.declares.CommandInfo(command));
43621                         });
43622                     };
43623                     Execution.prototype.open = function () {
43624                         var result = this.MyModal.open('SelectCommand');
43625                         console.log(result);
43626                     };
43627                     Execution.prototype.remove = function (index, list) {
43628                         list.splice(index, 1);
43629                     };
43630                     Execution.prototype.close = function () {
43631                         console.log("close");
43632                     };
43633                     Execution.$inject = ['MyModal', '$scope'];
43634                     return Execution;
43635                 })();
43636                 controllers.Execution = Execution;
43637             })(controllers = app.controllers || (app.controllers = {}));
43638         })(app || (app = {}));
43639         var app;
43640         (function (app) {
43641             var controllers;
43642             (function (controllers) {
43643                 var Workspace = (function () {
43644                     function Workspace($scope, APIEndPoint, MyModal) {
43645                         this.$scope = $scope;
43646                         this.APIEndPoint = APIEndPoint;
43647                         this.MyModal = MyModal;
43648                         this.directoryList = [];
43649                         var controller = this;
43650                         var directoryList = this.directoryList;
43651                         var o = {
43652                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
43653                             name: '',
43654                             parentId: '',
43655                             fileType: '',
43656                             createdAt: '',
43657                             updatedAt: '',
43658                             path: '/'
43659                         };
43660                         directoryList.push(o);
43661                     }
43662                     Workspace.prototype.addDirectory = function (info, directoryList) {
43663                         directoryList.push(info);
43664                     };
43665                     Workspace.prototype.debug = function () {
43666                         this.MyModal.preview();
43667                     };
43668                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
43669                     return Workspace;
43670                 })();
43671                 controllers.Workspace = Workspace;
43672             })(controllers = app.controllers || (app.controllers = {}));
43673         })(app || (app = {}));
43674         var app;
43675         (function (app) {
43676             var controllers;
43677             (function (controllers) {
43678                 var History = (function () {
43679                     function History($scope) {
43680                         this.page = "History";
43681                     }
43682                     History.$inject = ['$scope'];
43683                     return History;
43684                 })();
43685                 controllers.History = History;
43686             })(controllers = app.controllers || (app.controllers = {}));
43687         })(app || (app = {}));
43688         var app;
43689         (function (app) {
43690             var controllers;
43691             (function (controllers) {
43692                 var SelectCommand = (function () {
43693                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
43694                         this.APIEndPoint = APIEndPoint;
43695                         this.$modalInstance = $modalInstance;
43696                         var controller = this;
43697                         this.APIEndPoint
43698                             .getTags()
43699                             .$promise.then(function (result) {
43700                             controller.tags = result.info;
43701                         });
43702                         this.APIEndPoint
43703                             .getCommands()
43704                             .$promise.then(function (result) {
43705                             controller.commands = result.info;
43706                         });
43707                         this.currentTag = 'all';
43708                     }
43709                     SelectCommand.prototype.changeTag = function (tag) {
43710                         this.currentTag = tag;
43711                     };
43712                     SelectCommand.prototype.selectCommand = function (command) {
43713                         this.$modalInstance.close(command);
43714                     };
43715                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43716                     return SelectCommand;
43717                 })();
43718                 controllers.SelectCommand = SelectCommand;
43719             })(controllers = app.controllers || (app.controllers = {}));
43720         })(app || (app = {}));
43721         var app;
43722         (function (app) {
43723             var controllers;
43724             (function (controllers) {
43725                 var Preview = (function () {
43726                     function Preview($scope, APIEndPoint, $modalInstance) {
43727                         this.APIEndPoint = APIEndPoint;
43728                         this.$modalInstance = $modalInstance;
43729                         var controller = this;
43730                         console.log('preview');
43731                     }
43732                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43733                     return Preview;
43734                 })();
43735                 controllers.Preview = Preview;
43736             })(controllers = app.controllers || (app.controllers = {}));
43737         })(app || (app = {}));
43738         var filters;
43739         (function (filters) {
43740             function Tag() {
43741                 return function (commands, tag) {
43742                     var result = [];
43743                     angular.forEach(commands, function (command) {
43744                         var flag = false;
43745                         angular.forEach(command.tags, function (value) {
43746                             if (tag === value)
43747                                 flag = true;
43748                         });
43749                         if (flag)
43750                             result.push(command);
43751                     });
43752                     return result;
43753                 };
43754             }
43755             filters.Tag = Tag;
43756         })(filters || (filters = {}));
43757         var app;
43758         (function (app) {
43759             'use strict';
43760             var appName = 'zephyr';
43761             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
43762             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
43763                 $urlRouterProvider.otherwise('/execution');
43764                 $locationProvider.html5Mode({
43765                     enabled: true,
43766                     requireBase: false
43767                 });
43768                 $stateProvider
43769                     .state('execution', {
43770                     url: '/execution',
43771                     templateUrl: 'templates/execution.html',
43772                     controller: 'executionController',
43773                     controllerAs: 'c'
43774                 })
43775                     .state('workspace', {
43776                     url: '/workspace',
43777                     templateUrl: 'templates/workspace.html',
43778                     controller: 'workspaceController',
43779                     controllerAs: 'c'
43780                 })
43781                     .state('history', {
43782                     url: '/history',
43783                     templateUrl: 'templates/history.html',
43784                     controller: 'historyController',
43785                     controllerAs: 'c'
43786                 });
43787             });
43788             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
43789             app.zephyr.service('MyModal', app.services.MyModal);
43790             app.zephyr.service('WebSocket', app.services.WebSocket);
43791             app.zephyr.service('Console', app.services.Console);
43792             app.zephyr.filter('Tag', filters.Tag);
43793             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
43794             app.zephyr.controller('previewController', app.controllers.Preview);
43795             app.zephyr.controller('executionController', app.controllers.Execution);
43796             app.zephyr.controller('workspaceController', app.controllers.Workspace);
43797             app.zephyr.controller('historyController', app.controllers.History);
43798             app.zephyr.controller('commandController', app.directives.CommandController);
43799             app.zephyr.controller('optionController', app.directives.OptionController);
43800             app.zephyr.controller('directoryController', app.directives.DirectoryController);
43801             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
43802             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
43803             app.zephyr.directive('command', app.directives.Command.Factory());
43804             app.zephyr.directive('option', app.directives.Option.Factory());
43805             app.zephyr.directive('directory', app.directives.Directory.Factory());
43806         })(app || (app = {}));
43807
43808
43809 /***/ },
43810 /* 12 */
43811 /***/ function(module, exports) {
43812
43813         var app;
43814         (function (app) {
43815             var declares;
43816             (function (declares) {
43817                 var CommandInfo = (function () {
43818                     function CommandInfo(name) {
43819                         this.name = name;
43820                     }
43821                     return CommandInfo;
43822                 })();
43823                 declares.CommandInfo = CommandInfo;
43824             })(declares = app.declares || (app.declares = {}));
43825         })(app || (app = {}));
43826         var app;
43827         (function (app) {
43828             var services;
43829             (function (services) {
43830                 var APIEndPoint = (function () {
43831                     function APIEndPoint($resource, $http) {
43832                         this.$resource = $resource;
43833                         this.$http = $http;
43834                     }
43835                     APIEndPoint.prototype.resource = function (endPoint, data) {
43836                         var customAction = {
43837                             method: 'GET',
43838                             isArray: false
43839                         };
43840                         var execute = {
43841                             method: 'POST',
43842                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
43843                         };
43844                         return this.$resource(endPoint, {}, { execute: execute });
43845                     };
43846                     APIEndPoint.prototype.getOptionControlFile = function (command) {
43847                         var endPoint = '/api/v1/optionControlFile/' + command;
43848                         return this.resource(endPoint, {}).get();
43849                     };
43850                     APIEndPoint.prototype.getFiles = function (fileId) {
43851                         var endPoint = '/api/v1/workspace';
43852                         if (fileId) {
43853                             endPoint += '/' + fileId;
43854                         }
43855                         return this.resource(endPoint, {}).get();
43856                     };
43857                     APIEndPoint.prototype.getDirectories = function () {
43858                         var endPoint = '/api/v1/all/workspace/directory';
43859                         return this.resource(endPoint, {}).get();
43860                     };
43861                     APIEndPoint.prototype.getTags = function () {
43862                         var endPoint = '/api/v1/tagList';
43863                         return this.resource(endPoint, {}).get();
43864                     };
43865                     APIEndPoint.prototype.getCommands = function () {
43866                         var endPoint = '/api/v1/commandList';
43867                         return this.resource(endPoint, {}).get();
43868                     };
43869                     APIEndPoint.prototype.execute = function (data) {
43870                         var endPoint = '/api/v1/execution';
43871                         var fd = new FormData();
43872                         fd.append('data', data);
43873                         return this.$http.post(endPoint, fd, {
43874                             headers: { 'Content-Type': undefined },
43875                             transformRequest: angular.identity
43876                         });
43877                     };
43878                     APIEndPoint.prototype.debug = function () {
43879                         var endPoint = '/api/v1/debug';
43880                         return this.$http.get(endPoint);
43881                     };
43882                     APIEndPoint.prototype.help = function (command) {
43883                         var endPoint = '/api/v1/help/' + command;
43884                         return this.$http.get(endPoint);
43885                     };
43886                     return APIEndPoint;
43887                 })();
43888                 services.APIEndPoint = APIEndPoint;
43889             })(services = app.services || (app.services = {}));
43890         })(app || (app = {}));
43891         var app;
43892         (function (app) {
43893             var services;
43894             (function (services) {
43895                 var MyModal = (function () {
43896                     function MyModal($uibModal) {
43897                         this.$uibModal = $uibModal;
43898                         this.modalOption = {
43899                             backdrop: true,
43900                             controller: null,
43901                             templateUrl: null,
43902                             size: null
43903                         };
43904                     }
43905                     MyModal.prototype.open = function (modalName) {
43906                         if (modalName === 'SelectCommand') {
43907                             this.modalOption.templateUrl = 'templates/select-command.html';
43908                             this.modalOption.size = 'lg';
43909                         }
43910                         return this.$uibModal.open(this.modalOption);
43911                     };
43912                     MyModal.prototype.selectCommand = function () {
43913                         this.modalOption.templateUrl = 'templates/select-command.html';
43914                         this.modalOption.controller = 'selectCommandController';
43915                         this.modalOption.controllerAs = 'c';
43916                         this.modalOption.size = 'lg';
43917                         return this.$uibModal.open(this.modalOption);
43918                     };
43919                     MyModal.prototype.preview = function () {
43920                         this.modalOption.templateUrl = 'templates/preview.html';
43921                         this.modalOption.controller = 'previewController';
43922                         this.modalOption.controllerAs = 'c';
43923                         this.modalOption.size = 'lg';
43924                         return this.$uibModal.open(this.modalOption);
43925                     };
43926                     MyModal.$inject = ['$uibModal'];
43927                     return MyModal;
43928                 })();
43929                 services.MyModal = MyModal;
43930             })(services = app.services || (app.services = {}));
43931         })(app || (app = {}));
43932         var app;
43933         (function (app) {
43934             var services;
43935             (function (services) {
43936                 var WebSocket = (function () {
43937                     function WebSocket($rootScope) {
43938                         this.$rootScope = $rootScope;
43939                         this.socket = io.connect();
43940                     }
43941                     WebSocket.prototype.on = function (eventName, callback) {
43942                         var socket = this.socket;
43943                         var rootScope = this.$rootScope;
43944                         socket.on(eventName, function () {
43945                             var args = arguments;
43946                             rootScope.$apply(function () {
43947                                 callback.apply(socket, args);
43948                             });
43949                         });
43950                     };
43951                     WebSocket.prototype.emit = function (eventName, data, callback) {
43952                         var socket = this.socket;
43953                         var rootScope = this.$rootScope;
43954                         this.socket.emit(eventName, data, function () {
43955                             var args = arguments;
43956                             rootScope.$apply(function () {
43957                                 if (callback)
43958                                     callback.apply(socket, args);
43959                             });
43960                         });
43961                     };
43962                     return WebSocket;
43963                 })();
43964                 services.WebSocket = WebSocket;
43965             })(services = app.services || (app.services = {}));
43966         })(app || (app = {}));
43967         var app;
43968         (function (app) {
43969             var services;
43970             (function (services) {
43971                 var Console = (function () {
43972                     function Console(WebSocket, $rootScope) {
43973                         this.WebSocket = WebSocket;
43974                         this.$rootScope = $rootScope;
43975                         this.WebSocket = WebSocket;
43976                         this.$rootScope = $rootScope;
43977                         this.directiveIDs = [];
43978                         var directiveIDs = this.directiveIDs;
43979                         this.WebSocket.on('console', function (d) {
43980                             var id = d.id;
43981                             var message = d.message;
43982                             if (directiveIDs.indexOf(id) > -1) {
43983                                 $rootScope.$emit(id, message);
43984                             }
43985                         });
43986                     }
43987                     Console.prototype.addDirective = function (id) {
43988                         if (!(this.directiveIDs.indexOf(id) > -1)) {
43989                             this.directiveIDs.push(id);
43990                         }
43991                     };
43992                     Console.prototype.removeDirective = function (id) {
43993                         var i = this.directiveIDs.indexOf(id);
43994                         if (i > -1) {
43995                             this.directiveIDs.splice(i, 1);
43996                         }
43997                     };
43998                     Console.prototype.showIDs = function () {
43999                         console.log(this.directiveIDs);
44000                     };
44001                     return Console;
44002                 })();
44003                 services.Console = Console;
44004             })(services = app.services || (app.services = {}));
44005         })(app || (app = {}));
44006         var app;
44007         (function (app) {
44008             var directives;
44009             (function (directives) {
44010                 var Command = (function () {
44011                     function Command() {
44012                         this.restrict = 'E';
44013                         this.replace = true;
44014                         this.scope = true;
44015                         this.controller = 'commandController';
44016                         this.controllerAs = 'ctrl';
44017                         this.bindToController = {
44018                             index: '=',
44019                             name: '=',
44020                             remove: '&',
44021                             list: '='
44022                         };
44023                         this.templateUrl = 'templates/command.html';
44024                     }
44025                     Command.Factory = function () {
44026                         var directive = function () {
44027                             return new Command();
44028                         };
44029                         directive.$inject = [];
44030                         return directive;
44031                     };
44032                     return Command;
44033                 })();
44034                 directives.Command = Command;
44035                 var CommandController = (function () {
44036                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
44037                         this.APIEndPoint = APIEndPoint;
44038                         this.$scope = $scope;
44039                         this.MyModal = MyModal;
44040                         this.WebSocket = WebSocket;
44041                         this.$window = $window;
44042                         this.$rootScope = $rootScope;
44043                         this.Console = Console;
44044                         var controller = this;
44045                         this.APIEndPoint
44046                             .getOptionControlFile(this.name)
44047                             .$promise
44048                             .then(function (result) {
44049                             controller.options = result.info;
44050                         });
44051                         this.APIEndPoint
44052                             .getDirectories()
44053                             .$promise
44054                             .then(function (result) {
44055                             controller.dirs = result.info;
44056                         });
44057                         this.heading = "[" + this.index + "]: dcdFilePrint";
44058                         this.isOpen = true;
44059                         this.$scope.$on('close', function () {
44060                             controller.isOpen = false;
44061                         });
44062                         function guid() {
44063                             function s4() {
44064                                 return Math.floor((1 + Math.random()) * 0x10000)
44065                                     .toString(16)
44066                                     .substring(1);
44067                             }
44068                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
44069                                 s4() + '-' + s4() + s4() + s4();
44070                         }
44071                         this.uuid = guid();
44072                         this.Console.addDirective(this.uuid);
44073                         this.Console.showIDs();
44074                     }
44075                     CommandController.prototype.submit = function () {
44076                         var opt = [];
44077                         angular.forEach(this.options, function (option) {
44078                             var obj = {
44079                                 name: option.option,
44080                                 arguments: []
44081                             };
44082                             angular.forEach(option.arg, function (arg) {
44083                                 if (arg.input) {
44084                                     if (typeof arg.input === 'object') {
44085                                         obj.arguments.push(arg.input.name);
44086                                     }
44087                                     else {
44088                                         obj.arguments.push(arg.input);
44089                                     }
44090                                 }
44091                             });
44092                             if (obj.arguments.length > 0) {
44093                                 opt.push(obj);
44094                             }
44095                         });
44096                         var execObj = {
44097                             command: this.name,
44098                             workspace: this.workspace.fileId,
44099                             options: opt
44100                         };
44101                         this.APIEndPoint
44102                             .execute(JSON.stringify(execObj))
44103                             .then(function (result) {
44104                             console.log(result);
44105                         });
44106                     };
44107                     CommandController.prototype.removeMySelf = function (index) {
44108                         this.$scope.$destroy();
44109                         this.Console.removeDirective(this.uuid);
44110                         this.remove()(index, this.list);
44111                         this.Console.showIDs();
44112                     };
44113                     CommandController.prototype.reloadFiles = function () {
44114                         var _this = this;
44115                         var fileId = this.workspace.fileId;
44116                         this.APIEndPoint
44117                             .getFiles(fileId)
44118                             .$promise
44119                             .then(function (result) {
44120                             var status = result.status;
44121                             if (status === 'success') {
44122                                 _this.files = result.info;
44123                             }
44124                             else {
44125                                 console.log(result.message);
44126                             }
44127                         });
44128                     };
44129                     CommandController.prototype.debug = function () {
44130                         var div = angular.element(this.$window.document).find("div");
44131                         var consoleTag;
44132                         var parametersTag;
44133                         angular.forEach(div, function (v) {
44134                             if (v.className === "panel-body console") {
44135                                 consoleTag = v;
44136                             }
44137                             else if (v.className === "row parameters-console") {
44138                                 parametersTag = v;
44139                             }
44140                         });
44141                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
44142                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
44143                         consoleTag.style.height = consoleHeight;
44144                         consoleTag.style.width = consoleWidth;
44145                     };
44146                     CommandController.prototype.help = function () {
44147                         this.APIEndPoint
44148                             .help(this.name)
44149                             .then(function (result) {
44150                             console.log(result);
44151                         });
44152                     };
44153                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
44154                     return CommandController;
44155                 })();
44156                 directives.CommandController = CommandController;
44157             })(directives = app.directives || (app.directives = {}));
44158         })(app || (app = {}));
44159         var app;
44160         (function (app) {
44161             var directives;
44162             (function (directives) {
44163                 var HeaderMenu = (function () {
44164                     function HeaderMenu() {
44165                         this.restrict = 'E';
44166                         this.replace = true;
44167                         this.templateUrl = 'templates/header-menu.html';
44168                         this.controller = 'HeaderMenuController';
44169                         this.controllerAs = 'hmc';
44170                         this.scope = true;
44171                     }
44172                     HeaderMenu.Factory = function () {
44173                         var directive = function () {
44174                             return new HeaderMenu();
44175                         };
44176                         return directive;
44177                     };
44178                     return HeaderMenu;
44179                 })();
44180                 directives.HeaderMenu = HeaderMenu;
44181                 var HeaderMenuController = (function () {
44182                     function HeaderMenuController($state) {
44183                         this.$state = $state;
44184                         this.isExecution = this.$state.current.name === 'execution';
44185                         this.isWorkspace = this.$state.current.name === 'workspace';
44186                         this.isHistory = this.$state.current.name === 'history';
44187                     }
44188                     HeaderMenuController.prototype.transit = function (state) {
44189                         this.$state.go(state);
44190                     };
44191                     HeaderMenuController.$inject = ['$state'];
44192                     return HeaderMenuController;
44193                 })();
44194                 directives.HeaderMenuController = HeaderMenuController;
44195             })(directives = app.directives || (app.directives = {}));
44196         })(app || (app = {}));
44197         var app;
44198         (function (app) {
44199             var directives;
44200             (function (directives) {
44201                 var Option = (function () {
44202                     function Option() {
44203                         this.restrict = 'E';
44204                         this.replace = true;
44205                         this.controller = 'optionController';
44206                         this.bindToController = {
44207                             info: '=',
44208                             files: '='
44209                         };
44210                         this.scope = true;
44211                         this.templateUrl = 'templates/option.html';
44212                         this.controllerAs = 'ctrl';
44213                     }
44214                     Option.Factory = function () {
44215                         var directive = function () {
44216                             return new Option();
44217                         };
44218                         directive.$inject = [];
44219                         return directive;
44220                     };
44221                     return Option;
44222                 })();
44223                 directives.Option = Option;
44224                 var OptionController = (function () {
44225                     function OptionController() {
44226                         var controller = this;
44227                         angular.forEach(controller.info.arg, function (arg) {
44228                             if (arg.initialValue) {
44229                                 if (arg.formType === 'number') {
44230                                     arg.input = parseInt(arg.initialValue);
44231                                 }
44232                                 else {
44233                                     arg.input = arg.initialValue;
44234                                 }
44235                             }
44236                         });
44237                     }
44238                     OptionController.$inject = [];
44239                     return OptionController;
44240                 })();
44241                 directives.OptionController = OptionController;
44242             })(directives = app.directives || (app.directives = {}));
44243         })(app || (app = {}));
44244         var app;
44245         (function (app) {
44246             var directives;
44247             (function (directives) {
44248                 var Directory = (function () {
44249                     function Directory() {
44250                         this.restrict = 'E';
44251                         this.replace = true;
44252                         this.controller = 'directoryController';
44253                         this.controllerAs = 'ctrl';
44254                         this.bindToController = {
44255                             info: '=',
44256                             add: '&',
44257                             list: '=',
44258                             files: '='
44259                         };
44260                         this.templateUrl = 'templates/directory.html';
44261                     }
44262                     Directory.Factory = function () {
44263                         var directive = function () {
44264                             return new Directory();
44265                         };
44266                         return directive;
44267                     };
44268                     return Directory;
44269                 })();
44270                 directives.Directory = Directory;
44271                 var DirectoryController = (function () {
44272                     function DirectoryController(APIEndPoint, $scope) {
44273                         this.APIEndPoint = APIEndPoint;
44274                         this.$scope = $scope;
44275                         var controller = this;
44276                         this.APIEndPoint
44277                             .getFiles(this.info.fileId)
44278                             .$promise
44279                             .then(function (result) {
44280                             if (result.status === 'success') {
44281                                 controller.files = result.info;
44282                                 angular.forEach(result.info, function (file) {
44283                                     if (file.fileType === '0') {
44284                                         var o = file;
44285                                         if (controller.info.path === '/') {
44286                                             o.path = '/' + file.name;
44287                                         }
44288                                         else {
44289                                             o.path = controller.info.path + '/' + file.name;
44290                                         }
44291                                         controller.add()(o, controller.list);
44292                                     }
44293                                 });
44294                             }
44295                             ;
44296                         });
44297                     }
44298                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
44299                     return DirectoryController;
44300                 })();
44301                 directives.DirectoryController = DirectoryController;
44302             })(directives = app.directives || (app.directives = {}));
44303         })(app || (app = {}));
44304         var app;
44305         (function (app) {
44306             var controllers;
44307             (function (controllers) {
44308                 var Execution = (function () {
44309                     function Execution(MyModal, $scope) {
44310                         this.MyModal = MyModal;
44311                         this.$scope = $scope;
44312                         this.commandInfoList = [];
44313                     }
44314                     ;
44315                     Execution.prototype.add = function () {
44316                         this.$scope.$broadcast('close');
44317                         var commandInfoList = this.commandInfoList;
44318                         var commandInstance = this.MyModal.selectCommand();
44319                         commandInstance
44320                             .result
44321                             .then(function (command) {
44322                             commandInfoList.push(new app.declares.CommandInfo(command));
44323                         });
44324                     };
44325                     Execution.prototype.open = function () {
44326                         var result = this.MyModal.open('SelectCommand');
44327                         console.log(result);
44328                     };
44329                     Execution.prototype.remove = function (index, list) {
44330                         list.splice(index, 1);
44331                     };
44332                     Execution.prototype.close = function () {
44333                         console.log("close");
44334                     };
44335                     Execution.$inject = ['MyModal', '$scope'];
44336                     return Execution;
44337                 })();
44338                 controllers.Execution = Execution;
44339             })(controllers = app.controllers || (app.controllers = {}));
44340         })(app || (app = {}));
44341         var app;
44342         (function (app) {
44343             var controllers;
44344             (function (controllers) {
44345                 var Workspace = (function () {
44346                     function Workspace($scope, APIEndPoint, MyModal) {
44347                         this.$scope = $scope;
44348                         this.APIEndPoint = APIEndPoint;
44349                         this.MyModal = MyModal;
44350                         this.directoryList = [];
44351                         var controller = this;
44352                         var directoryList = this.directoryList;
44353                         var o = {
44354                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
44355                             name: '',
44356                             parentId: '',
44357                             fileType: '',
44358                             createdAt: '',
44359                             updatedAt: '',
44360                             path: '/'
44361                         };
44362                         directoryList.push(o);
44363                     }
44364                     Workspace.prototype.addDirectory = function (info, directoryList) {
44365                         directoryList.push(info);
44366                     };
44367                     Workspace.prototype.debug = function () {
44368                         this.MyModal.preview();
44369                     };
44370                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
44371                     return Workspace;
44372                 })();
44373                 controllers.Workspace = Workspace;
44374             })(controllers = app.controllers || (app.controllers = {}));
44375         })(app || (app = {}));
44376         var app;
44377         (function (app) {
44378             var controllers;
44379             (function (controllers) {
44380                 var History = (function () {
44381                     function History($scope) {
44382                         this.page = "History";
44383                     }
44384                     History.$inject = ['$scope'];
44385                     return History;
44386                 })();
44387                 controllers.History = History;
44388             })(controllers = app.controllers || (app.controllers = {}));
44389         })(app || (app = {}));
44390         var app;
44391         (function (app) {
44392             var controllers;
44393             (function (controllers) {
44394                 var SelectCommand = (function () {
44395                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
44396                         this.APIEndPoint = APIEndPoint;
44397                         this.$modalInstance = $modalInstance;
44398                         var controller = this;
44399                         this.APIEndPoint
44400                             .getTags()
44401                             .$promise.then(function (result) {
44402                             controller.tags = result.info;
44403                         });
44404                         this.APIEndPoint
44405                             .getCommands()
44406                             .$promise.then(function (result) {
44407                             controller.commands = result.info;
44408                         });
44409                         this.currentTag = 'all';
44410                     }
44411                     SelectCommand.prototype.changeTag = function (tag) {
44412                         this.currentTag = tag;
44413                     };
44414                     SelectCommand.prototype.selectCommand = function (command) {
44415                         this.$modalInstance.close(command);
44416                     };
44417                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44418                     return SelectCommand;
44419                 })();
44420                 controllers.SelectCommand = SelectCommand;
44421             })(controllers = app.controllers || (app.controllers = {}));
44422         })(app || (app = {}));
44423         var app;
44424         (function (app) {
44425             var controllers;
44426             (function (controllers) {
44427                 var Preview = (function () {
44428                     function Preview($scope, APIEndPoint, $modalInstance) {
44429                         this.APIEndPoint = APIEndPoint;
44430                         this.$modalInstance = $modalInstance;
44431                         var controller = this;
44432                         console.log('preview');
44433                     }
44434                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44435                     return Preview;
44436                 })();
44437                 controllers.Preview = Preview;
44438             })(controllers = app.controllers || (app.controllers = {}));
44439         })(app || (app = {}));
44440         var filters;
44441         (function (filters) {
44442             function Tag() {
44443                 return function (commands, tag) {
44444                     var result = [];
44445                     angular.forEach(commands, function (command) {
44446                         var flag = false;
44447                         angular.forEach(command.tags, function (value) {
44448                             if (tag === value)
44449                                 flag = true;
44450                         });
44451                         if (flag)
44452                             result.push(command);
44453                     });
44454                     return result;
44455                 };
44456             }
44457             filters.Tag = Tag;
44458         })(filters || (filters = {}));
44459         var app;
44460         (function (app) {
44461             'use strict';
44462             var appName = 'zephyr';
44463             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
44464             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
44465                 $urlRouterProvider.otherwise('/execution');
44466                 $locationProvider.html5Mode({
44467                     enabled: true,
44468                     requireBase: false
44469                 });
44470                 $stateProvider
44471                     .state('execution', {
44472                     url: '/execution',
44473                     templateUrl: 'templates/execution.html',
44474                     controller: 'executionController',
44475                     controllerAs: 'c'
44476                 })
44477                     .state('workspace', {
44478                     url: '/workspace',
44479                     templateUrl: 'templates/workspace.html',
44480                     controller: 'workspaceController',
44481                     controllerAs: 'c'
44482                 })
44483                     .state('history', {
44484                     url: '/history',
44485                     templateUrl: 'templates/history.html',
44486                     controller: 'historyController',
44487                     controllerAs: 'c'
44488                 });
44489             });
44490             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
44491             app.zephyr.service('MyModal', app.services.MyModal);
44492             app.zephyr.service('WebSocket', app.services.WebSocket);
44493             app.zephyr.service('Console', app.services.Console);
44494             app.zephyr.filter('Tag', filters.Tag);
44495             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
44496             app.zephyr.controller('previewController', app.controllers.Preview);
44497             app.zephyr.controller('executionController', app.controllers.Execution);
44498             app.zephyr.controller('workspaceController', app.controllers.Workspace);
44499             app.zephyr.controller('historyController', app.controllers.History);
44500             app.zephyr.controller('commandController', app.directives.CommandController);
44501             app.zephyr.controller('optionController', app.directives.OptionController);
44502             app.zephyr.controller('directoryController', app.directives.DirectoryController);
44503             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
44504             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
44505             app.zephyr.directive('command', app.directives.Command.Factory());
44506             app.zephyr.directive('option', app.directives.Option.Factory());
44507             app.zephyr.directive('directory', app.directives.Directory.Factory());
44508         })(app || (app = {}));
44509
44510
44511 /***/ },
44512 /* 13 */
44513 /***/ function(module, exports) {
44514
44515         var app;
44516         (function (app) {
44517             var declares;
44518             (function (declares) {
44519                 var CommandInfo = (function () {
44520                     function CommandInfo(name) {
44521                         this.name = name;
44522                     }
44523                     return CommandInfo;
44524                 })();
44525                 declares.CommandInfo = CommandInfo;
44526             })(declares = app.declares || (app.declares = {}));
44527         })(app || (app = {}));
44528         var app;
44529         (function (app) {
44530             var services;
44531             (function (services) {
44532                 var APIEndPoint = (function () {
44533                     function APIEndPoint($resource, $http) {
44534                         this.$resource = $resource;
44535                         this.$http = $http;
44536                     }
44537                     APIEndPoint.prototype.resource = function (endPoint, data) {
44538                         var customAction = {
44539                             method: 'GET',
44540                             isArray: false
44541                         };
44542                         var execute = {
44543                             method: 'POST',
44544                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
44545                         };
44546                         return this.$resource(endPoint, {}, { execute: execute });
44547                     };
44548                     APIEndPoint.prototype.getOptionControlFile = function (command) {
44549                         var endPoint = '/api/v1/optionControlFile/' + command;
44550                         return this.resource(endPoint, {}).get();
44551                     };
44552                     APIEndPoint.prototype.getFiles = function (fileId) {
44553                         var endPoint = '/api/v1/workspace';
44554                         if (fileId) {
44555                             endPoint += '/' + fileId;
44556                         }
44557                         return this.resource(endPoint, {}).get();
44558                     };
44559                     APIEndPoint.prototype.getDirectories = function () {
44560                         var endPoint = '/api/v1/all/workspace/directory';
44561                         return this.resource(endPoint, {}).get();
44562                     };
44563                     APIEndPoint.prototype.getTags = function () {
44564                         var endPoint = '/api/v1/tagList';
44565                         return this.resource(endPoint, {}).get();
44566                     };
44567                     APIEndPoint.prototype.getCommands = function () {
44568                         var endPoint = '/api/v1/commandList';
44569                         return this.resource(endPoint, {}).get();
44570                     };
44571                     APIEndPoint.prototype.execute = function (data) {
44572                         var endPoint = '/api/v1/execution';
44573                         var fd = new FormData();
44574                         fd.append('data', data);
44575                         return this.$http.post(endPoint, fd, {
44576                             headers: { 'Content-Type': undefined },
44577                             transformRequest: angular.identity
44578                         });
44579                     };
44580                     APIEndPoint.prototype.debug = function () {
44581                         var endPoint = '/api/v1/debug';
44582                         return this.$http.get(endPoint);
44583                     };
44584                     APIEndPoint.prototype.help = function (command) {
44585                         var endPoint = '/api/v1/help/' + command;
44586                         return this.$http.get(endPoint);
44587                     };
44588                     return APIEndPoint;
44589                 })();
44590                 services.APIEndPoint = APIEndPoint;
44591             })(services = app.services || (app.services = {}));
44592         })(app || (app = {}));
44593         var app;
44594         (function (app) {
44595             var services;
44596             (function (services) {
44597                 var MyModal = (function () {
44598                     function MyModal($uibModal) {
44599                         this.$uibModal = $uibModal;
44600                         this.modalOption = {
44601                             backdrop: true,
44602                             controller: null,
44603                             templateUrl: null,
44604                             size: null
44605                         };
44606                     }
44607                     MyModal.prototype.open = function (modalName) {
44608                         if (modalName === 'SelectCommand') {
44609                             this.modalOption.templateUrl = 'templates/select-command.html';
44610                             this.modalOption.size = 'lg';
44611                         }
44612                         return this.$uibModal.open(this.modalOption);
44613                     };
44614                     MyModal.prototype.selectCommand = function () {
44615                         this.modalOption.templateUrl = 'templates/select-command.html';
44616                         this.modalOption.controller = 'selectCommandController';
44617                         this.modalOption.controllerAs = 'c';
44618                         this.modalOption.size = 'lg';
44619                         return this.$uibModal.open(this.modalOption);
44620                     };
44621                     MyModal.prototype.preview = function () {
44622                         this.modalOption.templateUrl = 'templates/preview.html';
44623                         this.modalOption.controller = 'previewController';
44624                         this.modalOption.controllerAs = 'c';
44625                         this.modalOption.size = 'lg';
44626                         return this.$uibModal.open(this.modalOption);
44627                     };
44628                     MyModal.$inject = ['$uibModal'];
44629                     return MyModal;
44630                 })();
44631                 services.MyModal = MyModal;
44632             })(services = app.services || (app.services = {}));
44633         })(app || (app = {}));
44634         var app;
44635         (function (app) {
44636             var services;
44637             (function (services) {
44638                 var WebSocket = (function () {
44639                     function WebSocket($rootScope) {
44640                         this.$rootScope = $rootScope;
44641                         this.socket = io.connect();
44642                     }
44643                     WebSocket.prototype.on = function (eventName, callback) {
44644                         var socket = this.socket;
44645                         var rootScope = this.$rootScope;
44646                         socket.on(eventName, function () {
44647                             var args = arguments;
44648                             rootScope.$apply(function () {
44649                                 callback.apply(socket, args);
44650                             });
44651                         });
44652                     };
44653                     WebSocket.prototype.emit = function (eventName, data, callback) {
44654                         var socket = this.socket;
44655                         var rootScope = this.$rootScope;
44656                         this.socket.emit(eventName, data, function () {
44657                             var args = arguments;
44658                             rootScope.$apply(function () {
44659                                 if (callback)
44660                                     callback.apply(socket, args);
44661                             });
44662                         });
44663                     };
44664                     return WebSocket;
44665                 })();
44666                 services.WebSocket = WebSocket;
44667             })(services = app.services || (app.services = {}));
44668         })(app || (app = {}));
44669         var app;
44670         (function (app) {
44671             var services;
44672             (function (services) {
44673                 var Console = (function () {
44674                     function Console(WebSocket, $rootScope) {
44675                         this.WebSocket = WebSocket;
44676                         this.$rootScope = $rootScope;
44677                         this.WebSocket = WebSocket;
44678                         this.$rootScope = $rootScope;
44679                         this.directiveIDs = [];
44680                         var directiveIDs = this.directiveIDs;
44681                         this.WebSocket.on('console', function (d) {
44682                             var id = d.id;
44683                             var message = d.message;
44684                             if (directiveIDs.indexOf(id) > -1) {
44685                                 $rootScope.$emit(id, message);
44686                             }
44687                         });
44688                     }
44689                     Console.prototype.addDirective = function (id) {
44690                         if (!(this.directiveIDs.indexOf(id) > -1)) {
44691                             this.directiveIDs.push(id);
44692                         }
44693                     };
44694                     Console.prototype.removeDirective = function (id) {
44695                         var i = this.directiveIDs.indexOf(id);
44696                         if (i > -1) {
44697                             this.directiveIDs.splice(i, 1);
44698                         }
44699                     };
44700                     Console.prototype.showIDs = function () {
44701                         console.log(this.directiveIDs);
44702                     };
44703                     return Console;
44704                 })();
44705                 services.Console = Console;
44706             })(services = app.services || (app.services = {}));
44707         })(app || (app = {}));
44708         var app;
44709         (function (app) {
44710             var directives;
44711             (function (directives) {
44712                 var Command = (function () {
44713                     function Command() {
44714                         this.restrict = 'E';
44715                         this.replace = true;
44716                         this.scope = true;
44717                         this.controller = 'commandController';
44718                         this.controllerAs = 'ctrl';
44719                         this.bindToController = {
44720                             index: '=',
44721                             name: '=',
44722                             remove: '&',
44723                             list: '='
44724                         };
44725                         this.templateUrl = 'templates/command.html';
44726                     }
44727                     Command.Factory = function () {
44728                         var directive = function () {
44729                             return new Command();
44730                         };
44731                         directive.$inject = [];
44732                         return directive;
44733                     };
44734                     return Command;
44735                 })();
44736                 directives.Command = Command;
44737                 var CommandController = (function () {
44738                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
44739                         this.APIEndPoint = APIEndPoint;
44740                         this.$scope = $scope;
44741                         this.MyModal = MyModal;
44742                         this.WebSocket = WebSocket;
44743                         this.$window = $window;
44744                         this.$rootScope = $rootScope;
44745                         this.Console = Console;
44746                         var controller = this;
44747                         this.APIEndPoint
44748                             .getOptionControlFile(this.name)
44749                             .$promise
44750                             .then(function (result) {
44751                             controller.options = result.info;
44752                         });
44753                         this.APIEndPoint
44754                             .getDirectories()
44755                             .$promise
44756                             .then(function (result) {
44757                             controller.dirs = result.info;
44758                         });
44759                         this.heading = "[" + this.index + "]: dcdFilePrint";
44760                         this.isOpen = true;
44761                         this.$scope.$on('close', function () {
44762                             controller.isOpen = false;
44763                         });
44764                         function guid() {
44765                             function s4() {
44766                                 return Math.floor((1 + Math.random()) * 0x10000)
44767                                     .toString(16)
44768                                     .substring(1);
44769                             }
44770                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
44771                                 s4() + '-' + s4() + s4() + s4();
44772                         }
44773                         this.uuid = guid();
44774                         this.Console.addDirective(this.uuid);
44775                         this.Console.showIDs();
44776                     }
44777                     CommandController.prototype.submit = function () {
44778                         var opt = [];
44779                         angular.forEach(this.options, function (option) {
44780                             var obj = {
44781                                 name: option.option,
44782                                 arguments: []
44783                             };
44784                             angular.forEach(option.arg, function (arg) {
44785                                 if (arg.input) {
44786                                     if (typeof arg.input === 'object') {
44787                                         obj.arguments.push(arg.input.name);
44788                                     }
44789                                     else {
44790                                         obj.arguments.push(arg.input);
44791                                     }
44792                                 }
44793                             });
44794                             if (obj.arguments.length > 0) {
44795                                 opt.push(obj);
44796                             }
44797                         });
44798                         var execObj = {
44799                             command: this.name,
44800                             workspace: this.workspace.fileId,
44801                             options: opt
44802                         };
44803                         this.APIEndPoint
44804                             .execute(JSON.stringify(execObj))
44805                             .then(function (result) {
44806                             console.log(result);
44807                         });
44808                     };
44809                     CommandController.prototype.removeMySelf = function (index) {
44810                         this.$scope.$destroy();
44811                         this.Console.removeDirective(this.uuid);
44812                         this.remove()(index, this.list);
44813                         this.Console.showIDs();
44814                     };
44815                     CommandController.prototype.reloadFiles = function () {
44816                         var _this = this;
44817                         var fileId = this.workspace.fileId;
44818                         this.APIEndPoint
44819                             .getFiles(fileId)
44820                             .$promise
44821                             .then(function (result) {
44822                             var status = result.status;
44823                             if (status === 'success') {
44824                                 _this.files = result.info;
44825                             }
44826                             else {
44827                                 console.log(result.message);
44828                             }
44829                         });
44830                     };
44831                     CommandController.prototype.debug = function () {
44832                         var div = angular.element(this.$window.document).find("div");
44833                         var consoleTag;
44834                         var parametersTag;
44835                         angular.forEach(div, function (v) {
44836                             if (v.className === "panel-body console") {
44837                                 consoleTag = v;
44838                             }
44839                             else if (v.className === "row parameters-console") {
44840                                 parametersTag = v;
44841                             }
44842                         });
44843                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
44844                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
44845                         consoleTag.style.height = consoleHeight;
44846                         consoleTag.style.width = consoleWidth;
44847                     };
44848                     CommandController.prototype.help = function () {
44849                         this.APIEndPoint
44850                             .help(this.name)
44851                             .then(function (result) {
44852                             console.log(result);
44853                         });
44854                     };
44855                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
44856                     return CommandController;
44857                 })();
44858                 directives.CommandController = CommandController;
44859             })(directives = app.directives || (app.directives = {}));
44860         })(app || (app = {}));
44861         var app;
44862         (function (app) {
44863             var directives;
44864             (function (directives) {
44865                 var HeaderMenu = (function () {
44866                     function HeaderMenu() {
44867                         this.restrict = 'E';
44868                         this.replace = true;
44869                         this.templateUrl = 'templates/header-menu.html';
44870                         this.controller = 'HeaderMenuController';
44871                         this.controllerAs = 'hmc';
44872                         this.scope = true;
44873                     }
44874                     HeaderMenu.Factory = function () {
44875                         var directive = function () {
44876                             return new HeaderMenu();
44877                         };
44878                         return directive;
44879                     };
44880                     return HeaderMenu;
44881                 })();
44882                 directives.HeaderMenu = HeaderMenu;
44883                 var HeaderMenuController = (function () {
44884                     function HeaderMenuController($state) {
44885                         this.$state = $state;
44886                         this.isExecution = this.$state.current.name === 'execution';
44887                         this.isWorkspace = this.$state.current.name === 'workspace';
44888                         this.isHistory = this.$state.current.name === 'history';
44889                     }
44890                     HeaderMenuController.prototype.transit = function (state) {
44891                         this.$state.go(state);
44892                     };
44893                     HeaderMenuController.$inject = ['$state'];
44894                     return HeaderMenuController;
44895                 })();
44896                 directives.HeaderMenuController = HeaderMenuController;
44897             })(directives = app.directives || (app.directives = {}));
44898         })(app || (app = {}));
44899         var app;
44900         (function (app) {
44901             var directives;
44902             (function (directives) {
44903                 var Option = (function () {
44904                     function Option() {
44905                         this.restrict = 'E';
44906                         this.replace = true;
44907                         this.controller = 'optionController';
44908                         this.bindToController = {
44909                             info: '=',
44910                             files: '='
44911                         };
44912                         this.scope = true;
44913                         this.templateUrl = 'templates/option.html';
44914                         this.controllerAs = 'ctrl';
44915                     }
44916                     Option.Factory = function () {
44917                         var directive = function () {
44918                             return new Option();
44919                         };
44920                         directive.$inject = [];
44921                         return directive;
44922                     };
44923                     return Option;
44924                 })();
44925                 directives.Option = Option;
44926                 var OptionController = (function () {
44927                     function OptionController() {
44928                         var controller = this;
44929                         angular.forEach(controller.info.arg, function (arg) {
44930                             if (arg.initialValue) {
44931                                 if (arg.formType === 'number') {
44932                                     arg.input = parseInt(arg.initialValue);
44933                                 }
44934                                 else {
44935                                     arg.input = arg.initialValue;
44936                                 }
44937                             }
44938                         });
44939                     }
44940                     OptionController.$inject = [];
44941                     return OptionController;
44942                 })();
44943                 directives.OptionController = OptionController;
44944             })(directives = app.directives || (app.directives = {}));
44945         })(app || (app = {}));
44946         var app;
44947         (function (app) {
44948             var directives;
44949             (function (directives) {
44950                 var Directory = (function () {
44951                     function Directory() {
44952                         this.restrict = 'E';
44953                         this.replace = true;
44954                         this.controller = 'directoryController';
44955                         this.controllerAs = 'ctrl';
44956                         this.bindToController = {
44957                             info: '=',
44958                             add: '&',
44959                             list: '=',
44960                             files: '='
44961                         };
44962                         this.templateUrl = 'templates/directory.html';
44963                     }
44964                     Directory.Factory = function () {
44965                         var directive = function () {
44966                             return new Directory();
44967                         };
44968                         return directive;
44969                     };
44970                     return Directory;
44971                 })();
44972                 directives.Directory = Directory;
44973                 var DirectoryController = (function () {
44974                     function DirectoryController(APIEndPoint, $scope) {
44975                         this.APIEndPoint = APIEndPoint;
44976                         this.$scope = $scope;
44977                         var controller = this;
44978                         this.APIEndPoint
44979                             .getFiles(this.info.fileId)
44980                             .$promise
44981                             .then(function (result) {
44982                             if (result.status === 'success') {
44983                                 controller.files = result.info;
44984                                 angular.forEach(result.info, function (file) {
44985                                     if (file.fileType === '0') {
44986                                         var o = file;
44987                                         if (controller.info.path === '/') {
44988                                             o.path = '/' + file.name;
44989                                         }
44990                                         else {
44991                                             o.path = controller.info.path + '/' + file.name;
44992                                         }
44993                                         controller.add()(o, controller.list);
44994                                     }
44995                                 });
44996                             }
44997                             ;
44998                         });
44999                     }
45000                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
45001                     return DirectoryController;
45002                 })();
45003                 directives.DirectoryController = DirectoryController;
45004             })(directives = app.directives || (app.directives = {}));
45005         })(app || (app = {}));
45006         var app;
45007         (function (app) {
45008             var controllers;
45009             (function (controllers) {
45010                 var Execution = (function () {
45011                     function Execution(MyModal, $scope) {
45012                         this.MyModal = MyModal;
45013                         this.$scope = $scope;
45014                         this.commandInfoList = [];
45015                     }
45016                     ;
45017                     Execution.prototype.add = function () {
45018                         this.$scope.$broadcast('close');
45019                         var commandInfoList = this.commandInfoList;
45020                         var commandInstance = this.MyModal.selectCommand();
45021                         commandInstance
45022                             .result
45023                             .then(function (command) {
45024                             commandInfoList.push(new app.declares.CommandInfo(command));
45025                         });
45026                     };
45027                     Execution.prototype.open = function () {
45028                         var result = this.MyModal.open('SelectCommand');
45029                         console.log(result);
45030                     };
45031                     Execution.prototype.remove = function (index, list) {
45032                         list.splice(index, 1);
45033                     };
45034                     Execution.prototype.close = function () {
45035                         console.log("close");
45036                     };
45037                     Execution.$inject = ['MyModal', '$scope'];
45038                     return Execution;
45039                 })();
45040                 controllers.Execution = Execution;
45041             })(controllers = app.controllers || (app.controllers = {}));
45042         })(app || (app = {}));
45043         var app;
45044         (function (app) {
45045             var controllers;
45046             (function (controllers) {
45047                 var Workspace = (function () {
45048                     function Workspace($scope, APIEndPoint, MyModal) {
45049                         this.$scope = $scope;
45050                         this.APIEndPoint = APIEndPoint;
45051                         this.MyModal = MyModal;
45052                         this.directoryList = [];
45053                         var controller = this;
45054                         var directoryList = this.directoryList;
45055                         var o = {
45056                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
45057                             name: '',
45058                             parentId: '',
45059                             fileType: '',
45060                             createdAt: '',
45061                             updatedAt: '',
45062                             path: '/'
45063                         };
45064                         directoryList.push(o);
45065                     }
45066                     Workspace.prototype.addDirectory = function (info, directoryList) {
45067                         directoryList.push(info);
45068                     };
45069                     Workspace.prototype.debug = function () {
45070                         this.MyModal.preview();
45071                     };
45072                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
45073                     return Workspace;
45074                 })();
45075                 controllers.Workspace = Workspace;
45076             })(controllers = app.controllers || (app.controllers = {}));
45077         })(app || (app = {}));
45078         var app;
45079         (function (app) {
45080             var controllers;
45081             (function (controllers) {
45082                 var History = (function () {
45083                     function History($scope) {
45084                         this.page = "History";
45085                     }
45086                     History.$inject = ['$scope'];
45087                     return History;
45088                 })();
45089                 controllers.History = History;
45090             })(controllers = app.controllers || (app.controllers = {}));
45091         })(app || (app = {}));
45092         var app;
45093         (function (app) {
45094             var controllers;
45095             (function (controllers) {
45096                 var SelectCommand = (function () {
45097                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
45098                         this.APIEndPoint = APIEndPoint;
45099                         this.$modalInstance = $modalInstance;
45100                         var controller = this;
45101                         this.APIEndPoint
45102                             .getTags()
45103                             .$promise.then(function (result) {
45104                             controller.tags = result.info;
45105                         });
45106                         this.APIEndPoint
45107                             .getCommands()
45108                             .$promise.then(function (result) {
45109                             controller.commands = result.info;
45110                         });
45111                         this.currentTag = 'all';
45112                     }
45113                     SelectCommand.prototype.changeTag = function (tag) {
45114                         this.currentTag = tag;
45115                     };
45116                     SelectCommand.prototype.selectCommand = function (command) {
45117                         this.$modalInstance.close(command);
45118                     };
45119                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45120                     return SelectCommand;
45121                 })();
45122                 controllers.SelectCommand = SelectCommand;
45123             })(controllers = app.controllers || (app.controllers = {}));
45124         })(app || (app = {}));
45125         var app;
45126         (function (app) {
45127             var controllers;
45128             (function (controllers) {
45129                 var Preview = (function () {
45130                     function Preview($scope, APIEndPoint, $modalInstance) {
45131                         this.APIEndPoint = APIEndPoint;
45132                         this.$modalInstance = $modalInstance;
45133                         var controller = this;
45134                         console.log('preview');
45135                     }
45136                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45137                     return Preview;
45138                 })();
45139                 controllers.Preview = Preview;
45140             })(controllers = app.controllers || (app.controllers = {}));
45141         })(app || (app = {}));
45142         var filters;
45143         (function (filters) {
45144             function Tag() {
45145                 return function (commands, tag) {
45146                     var result = [];
45147                     angular.forEach(commands, function (command) {
45148                         var flag = false;
45149                         angular.forEach(command.tags, function (value) {
45150                             if (tag === value)
45151                                 flag = true;
45152                         });
45153                         if (flag)
45154                             result.push(command);
45155                     });
45156                     return result;
45157                 };
45158             }
45159             filters.Tag = Tag;
45160         })(filters || (filters = {}));
45161         var app;
45162         (function (app) {
45163             'use strict';
45164             var appName = 'zephyr';
45165             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
45166             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
45167                 $urlRouterProvider.otherwise('/execution');
45168                 $locationProvider.html5Mode({
45169                     enabled: true,
45170                     requireBase: false
45171                 });
45172                 $stateProvider
45173                     .state('execution', {
45174                     url: '/execution',
45175                     templateUrl: 'templates/execution.html',
45176                     controller: 'executionController',
45177                     controllerAs: 'c'
45178                 })
45179                     .state('workspace', {
45180                     url: '/workspace',
45181                     templateUrl: 'templates/workspace.html',
45182                     controller: 'workspaceController',
45183                     controllerAs: 'c'
45184                 })
45185                     .state('history', {
45186                     url: '/history',
45187                     templateUrl: 'templates/history.html',
45188                     controller: 'historyController',
45189                     controllerAs: 'c'
45190                 });
45191             });
45192             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
45193             app.zephyr.service('MyModal', app.services.MyModal);
45194             app.zephyr.service('WebSocket', app.services.WebSocket);
45195             app.zephyr.service('Console', app.services.Console);
45196             app.zephyr.filter('Tag', filters.Tag);
45197             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
45198             app.zephyr.controller('previewController', app.controllers.Preview);
45199             app.zephyr.controller('executionController', app.controllers.Execution);
45200             app.zephyr.controller('workspaceController', app.controllers.Workspace);
45201             app.zephyr.controller('historyController', app.controllers.History);
45202             app.zephyr.controller('commandController', app.directives.CommandController);
45203             app.zephyr.controller('optionController', app.directives.OptionController);
45204             app.zephyr.controller('directoryController', app.directives.DirectoryController);
45205             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
45206             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
45207             app.zephyr.directive('command', app.directives.Command.Factory());
45208             app.zephyr.directive('option', app.directives.Option.Factory());
45209             app.zephyr.directive('directory', app.directives.Directory.Factory());
45210         })(app || (app = {}));
45211
45212
45213 /***/ },
45214 /* 14 */
45215 /***/ function(module, exports) {
45216
45217         var app;
45218         (function (app) {
45219             var declares;
45220             (function (declares) {
45221                 var CommandInfo = (function () {
45222                     function CommandInfo(name) {
45223                         this.name = name;
45224                     }
45225                     return CommandInfo;
45226                 })();
45227                 declares.CommandInfo = CommandInfo;
45228             })(declares = app.declares || (app.declares = {}));
45229         })(app || (app = {}));
45230         var app;
45231         (function (app) {
45232             var services;
45233             (function (services) {
45234                 var APIEndPoint = (function () {
45235                     function APIEndPoint($resource, $http) {
45236                         this.$resource = $resource;
45237                         this.$http = $http;
45238                     }
45239                     APIEndPoint.prototype.resource = function (endPoint, data) {
45240                         var customAction = {
45241                             method: 'GET',
45242                             isArray: false
45243                         };
45244                         var execute = {
45245                             method: 'POST',
45246                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
45247                         };
45248                         return this.$resource(endPoint, {}, { execute: execute });
45249                     };
45250                     APIEndPoint.prototype.getOptionControlFile = function (command) {
45251                         var endPoint = '/api/v1/optionControlFile/' + command;
45252                         return this.resource(endPoint, {}).get();
45253                     };
45254                     APIEndPoint.prototype.getFiles = function (fileId) {
45255                         var endPoint = '/api/v1/workspace';
45256                         if (fileId) {
45257                             endPoint += '/' + fileId;
45258                         }
45259                         return this.resource(endPoint, {}).get();
45260                     };
45261                     APIEndPoint.prototype.getDirectories = function () {
45262                         var endPoint = '/api/v1/all/workspace/directory';
45263                         return this.resource(endPoint, {}).get();
45264                     };
45265                     APIEndPoint.prototype.getTags = function () {
45266                         var endPoint = '/api/v1/tagList';
45267                         return this.resource(endPoint, {}).get();
45268                     };
45269                     APIEndPoint.prototype.getCommands = function () {
45270                         var endPoint = '/api/v1/commandList';
45271                         return this.resource(endPoint, {}).get();
45272                     };
45273                     APIEndPoint.prototype.execute = function (data) {
45274                         var endPoint = '/api/v1/execution';
45275                         var fd = new FormData();
45276                         fd.append('data', data);
45277                         return this.$http.post(endPoint, fd, {
45278                             headers: { 'Content-Type': undefined },
45279                             transformRequest: angular.identity
45280                         });
45281                     };
45282                     APIEndPoint.prototype.debug = function () {
45283                         var endPoint = '/api/v1/debug';
45284                         return this.$http.get(endPoint);
45285                     };
45286                     APIEndPoint.prototype.help = function (command) {
45287                         var endPoint = '/api/v1/help/' + command;
45288                         return this.$http.get(endPoint);
45289                     };
45290                     return APIEndPoint;
45291                 })();
45292                 services.APIEndPoint = APIEndPoint;
45293             })(services = app.services || (app.services = {}));
45294         })(app || (app = {}));
45295         var app;
45296         (function (app) {
45297             var services;
45298             (function (services) {
45299                 var MyModal = (function () {
45300                     function MyModal($uibModal) {
45301                         this.$uibModal = $uibModal;
45302                         this.modalOption = {
45303                             backdrop: true,
45304                             controller: null,
45305                             templateUrl: null,
45306                             size: null
45307                         };
45308                     }
45309                     MyModal.prototype.open = function (modalName) {
45310                         if (modalName === 'SelectCommand') {
45311                             this.modalOption.templateUrl = 'templates/select-command.html';
45312                             this.modalOption.size = 'lg';
45313                         }
45314                         return this.$uibModal.open(this.modalOption);
45315                     };
45316                     MyModal.prototype.selectCommand = function () {
45317                         this.modalOption.templateUrl = 'templates/select-command.html';
45318                         this.modalOption.controller = 'selectCommandController';
45319                         this.modalOption.controllerAs = 'c';
45320                         this.modalOption.size = 'lg';
45321                         return this.$uibModal.open(this.modalOption);
45322                     };
45323                     MyModal.prototype.preview = function () {
45324                         this.modalOption.templateUrl = 'templates/preview.html';
45325                         this.modalOption.controller = 'previewController';
45326                         this.modalOption.controllerAs = 'c';
45327                         this.modalOption.size = 'lg';
45328                         return this.$uibModal.open(this.modalOption);
45329                     };
45330                     MyModal.$inject = ['$uibModal'];
45331                     return MyModal;
45332                 })();
45333                 services.MyModal = MyModal;
45334             })(services = app.services || (app.services = {}));
45335         })(app || (app = {}));
45336         var app;
45337         (function (app) {
45338             var services;
45339             (function (services) {
45340                 var WebSocket = (function () {
45341                     function WebSocket($rootScope) {
45342                         this.$rootScope = $rootScope;
45343                         this.socket = io.connect();
45344                     }
45345                     WebSocket.prototype.on = function (eventName, callback) {
45346                         var socket = this.socket;
45347                         var rootScope = this.$rootScope;
45348                         socket.on(eventName, function () {
45349                             var args = arguments;
45350                             rootScope.$apply(function () {
45351                                 callback.apply(socket, args);
45352                             });
45353                         });
45354                     };
45355                     WebSocket.prototype.emit = function (eventName, data, callback) {
45356                         var socket = this.socket;
45357                         var rootScope = this.$rootScope;
45358                         this.socket.emit(eventName, data, function () {
45359                             var args = arguments;
45360                             rootScope.$apply(function () {
45361                                 if (callback)
45362                                     callback.apply(socket, args);
45363                             });
45364                         });
45365                     };
45366                     return WebSocket;
45367                 })();
45368                 services.WebSocket = WebSocket;
45369             })(services = app.services || (app.services = {}));
45370         })(app || (app = {}));
45371         var app;
45372         (function (app) {
45373             var services;
45374             (function (services) {
45375                 var Console = (function () {
45376                     function Console(WebSocket, $rootScope) {
45377                         this.WebSocket = WebSocket;
45378                         this.$rootScope = $rootScope;
45379                         this.WebSocket = WebSocket;
45380                         this.$rootScope = $rootScope;
45381                         this.directiveIDs = [];
45382                         var directiveIDs = this.directiveIDs;
45383                         this.WebSocket.on('console', function (d) {
45384                             var id = d.id;
45385                             var message = d.message;
45386                             if (directiveIDs.indexOf(id) > -1) {
45387                                 $rootScope.$emit(id, message);
45388                             }
45389                         });
45390                     }
45391                     Console.prototype.addDirective = function (id) {
45392                         if (!(this.directiveIDs.indexOf(id) > -1)) {
45393                             this.directiveIDs.push(id);
45394                         }
45395                     };
45396                     Console.prototype.removeDirective = function (id) {
45397                         var i = this.directiveIDs.indexOf(id);
45398                         if (i > -1) {
45399                             this.directiveIDs.splice(i, 1);
45400                         }
45401                     };
45402                     Console.prototype.showIDs = function () {
45403                         console.log(this.directiveIDs);
45404                     };
45405                     return Console;
45406                 })();
45407                 services.Console = Console;
45408             })(services = app.services || (app.services = {}));
45409         })(app || (app = {}));
45410         var app;
45411         (function (app) {
45412             var directives;
45413             (function (directives) {
45414                 var Command = (function () {
45415                     function Command() {
45416                         this.restrict = 'E';
45417                         this.replace = true;
45418                         this.scope = true;
45419                         this.controller = 'commandController';
45420                         this.controllerAs = 'ctrl';
45421                         this.bindToController = {
45422                             index: '=',
45423                             name: '=',
45424                             remove: '&',
45425                             list: '='
45426                         };
45427                         this.templateUrl = 'templates/command.html';
45428                     }
45429                     Command.Factory = function () {
45430                         var directive = function () {
45431                             return new Command();
45432                         };
45433                         directive.$inject = [];
45434                         return directive;
45435                     };
45436                     return Command;
45437                 })();
45438                 directives.Command = Command;
45439                 var CommandController = (function () {
45440                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
45441                         this.APIEndPoint = APIEndPoint;
45442                         this.$scope = $scope;
45443                         this.MyModal = MyModal;
45444                         this.WebSocket = WebSocket;
45445                         this.$window = $window;
45446                         this.$rootScope = $rootScope;
45447                         this.Console = Console;
45448                         var controller = this;
45449                         this.APIEndPoint
45450                             .getOptionControlFile(this.name)
45451                             .$promise
45452                             .then(function (result) {
45453                             controller.options = result.info;
45454                         });
45455                         this.APIEndPoint
45456                             .getDirectories()
45457                             .$promise
45458                             .then(function (result) {
45459                             controller.dirs = result.info;
45460                         });
45461                         this.heading = "[" + this.index + "]: dcdFilePrint";
45462                         this.isOpen = true;
45463                         this.$scope.$on('close', function () {
45464                             controller.isOpen = false;
45465                         });
45466                         function guid() {
45467                             function s4() {
45468                                 return Math.floor((1 + Math.random()) * 0x10000)
45469                                     .toString(16)
45470                                     .substring(1);
45471                             }
45472                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
45473                                 s4() + '-' + s4() + s4() + s4();
45474                         }
45475                         this.uuid = guid();
45476                         this.Console.addDirective(this.uuid);
45477                         this.Console.showIDs();
45478                     }
45479                     CommandController.prototype.submit = function () {
45480                         var opt = [];
45481                         angular.forEach(this.options, function (option) {
45482                             var obj = {
45483                                 name: option.option,
45484                                 arguments: []
45485                             };
45486                             angular.forEach(option.arg, function (arg) {
45487                                 if (arg.input) {
45488                                     if (typeof arg.input === 'object') {
45489                                         obj.arguments.push(arg.input.name);
45490                                     }
45491                                     else {
45492                                         obj.arguments.push(arg.input);
45493                                     }
45494                                 }
45495                             });
45496                             if (obj.arguments.length > 0) {
45497                                 opt.push(obj);
45498                             }
45499                         });
45500                         var execObj = {
45501                             command: this.name,
45502                             workspace: this.workspace.fileId,
45503                             options: opt
45504                         };
45505                         this.APIEndPoint
45506                             .execute(JSON.stringify(execObj))
45507                             .then(function (result) {
45508                             console.log(result);
45509                         });
45510                     };
45511                     CommandController.prototype.removeMySelf = function (index) {
45512                         this.$scope.$destroy();
45513                         this.Console.removeDirective(this.uuid);
45514                         this.remove()(index, this.list);
45515                         this.Console.showIDs();
45516                     };
45517                     CommandController.prototype.reloadFiles = function () {
45518                         var _this = this;
45519                         var fileId = this.workspace.fileId;
45520                         this.APIEndPoint
45521                             .getFiles(fileId)
45522                             .$promise
45523                             .then(function (result) {
45524                             var status = result.status;
45525                             if (status === 'success') {
45526                                 _this.files = result.info;
45527                             }
45528                             else {
45529                                 console.log(result.message);
45530                             }
45531                         });
45532                     };
45533                     CommandController.prototype.debug = function () {
45534                         var div = angular.element(this.$window.document).find("div");
45535                         var consoleTag;
45536                         var parametersTag;
45537                         angular.forEach(div, function (v) {
45538                             if (v.className === "panel-body console") {
45539                                 consoleTag = v;
45540                             }
45541                             else if (v.className === "row parameters-console") {
45542                                 parametersTag = v;
45543                             }
45544                         });
45545                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
45546                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
45547                         consoleTag.style.height = consoleHeight;
45548                         consoleTag.style.width = consoleWidth;
45549                     };
45550                     CommandController.prototype.help = function () {
45551                         this.APIEndPoint
45552                             .help(this.name)
45553                             .then(function (result) {
45554                             console.log(result);
45555                         });
45556                     };
45557                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
45558                     return CommandController;
45559                 })();
45560                 directives.CommandController = CommandController;
45561             })(directives = app.directives || (app.directives = {}));
45562         })(app || (app = {}));
45563         var app;
45564         (function (app) {
45565             var directives;
45566             (function (directives) {
45567                 var HeaderMenu = (function () {
45568                     function HeaderMenu() {
45569                         this.restrict = 'E';
45570                         this.replace = true;
45571                         this.templateUrl = 'templates/header-menu.html';
45572                         this.controller = 'HeaderMenuController';
45573                         this.controllerAs = 'hmc';
45574                         this.scope = true;
45575                     }
45576                     HeaderMenu.Factory = function () {
45577                         var directive = function () {
45578                             return new HeaderMenu();
45579                         };
45580                         return directive;
45581                     };
45582                     return HeaderMenu;
45583                 })();
45584                 directives.HeaderMenu = HeaderMenu;
45585                 var HeaderMenuController = (function () {
45586                     function HeaderMenuController($state) {
45587                         this.$state = $state;
45588                         this.isExecution = this.$state.current.name === 'execution';
45589                         this.isWorkspace = this.$state.current.name === 'workspace';
45590                         this.isHistory = this.$state.current.name === 'history';
45591                     }
45592                     HeaderMenuController.prototype.transit = function (state) {
45593                         this.$state.go(state);
45594                     };
45595                     HeaderMenuController.$inject = ['$state'];
45596                     return HeaderMenuController;
45597                 })();
45598                 directives.HeaderMenuController = HeaderMenuController;
45599             })(directives = app.directives || (app.directives = {}));
45600         })(app || (app = {}));
45601         var app;
45602         (function (app) {
45603             var directives;
45604             (function (directives) {
45605                 var Option = (function () {
45606                     function Option() {
45607                         this.restrict = 'E';
45608                         this.replace = true;
45609                         this.controller = 'optionController';
45610                         this.bindToController = {
45611                             info: '=',
45612                             files: '='
45613                         };
45614                         this.scope = true;
45615                         this.templateUrl = 'templates/option.html';
45616                         this.controllerAs = 'ctrl';
45617                     }
45618                     Option.Factory = function () {
45619                         var directive = function () {
45620                             return new Option();
45621                         };
45622                         directive.$inject = [];
45623                         return directive;
45624                     };
45625                     return Option;
45626                 })();
45627                 directives.Option = Option;
45628                 var OptionController = (function () {
45629                     function OptionController() {
45630                         var controller = this;
45631                         angular.forEach(controller.info.arg, function (arg) {
45632                             if (arg.initialValue) {
45633                                 if (arg.formType === 'number') {
45634                                     arg.input = parseInt(arg.initialValue);
45635                                 }
45636                                 else {
45637                                     arg.input = arg.initialValue;
45638                                 }
45639                             }
45640                         });
45641                     }
45642                     OptionController.$inject = [];
45643                     return OptionController;
45644                 })();
45645                 directives.OptionController = OptionController;
45646             })(directives = app.directives || (app.directives = {}));
45647         })(app || (app = {}));
45648         var app;
45649         (function (app) {
45650             var directives;
45651             (function (directives) {
45652                 var Directory = (function () {
45653                     function Directory() {
45654                         this.restrict = 'E';
45655                         this.replace = true;
45656                         this.controller = 'directoryController';
45657                         this.controllerAs = 'ctrl';
45658                         this.bindToController = {
45659                             info: '=',
45660                             add: '&',
45661                             list: '=',
45662                             files: '='
45663                         };
45664                         this.templateUrl = 'templates/directory.html';
45665                     }
45666                     Directory.Factory = function () {
45667                         var directive = function () {
45668                             return new Directory();
45669                         };
45670                         return directive;
45671                     };
45672                     return Directory;
45673                 })();
45674                 directives.Directory = Directory;
45675                 var DirectoryController = (function () {
45676                     function DirectoryController(APIEndPoint, $scope) {
45677                         this.APIEndPoint = APIEndPoint;
45678                         this.$scope = $scope;
45679                         var controller = this;
45680                         this.APIEndPoint
45681                             .getFiles(this.info.fileId)
45682                             .$promise
45683                             .then(function (result) {
45684                             if (result.status === 'success') {
45685                                 controller.files = result.info;
45686                                 angular.forEach(result.info, function (file) {
45687                                     if (file.fileType === '0') {
45688                                         var o = file;
45689                                         if (controller.info.path === '/') {
45690                                             o.path = '/' + file.name;
45691                                         }
45692                                         else {
45693                                             o.path = controller.info.path + '/' + file.name;
45694                                         }
45695                                         controller.add()(o, controller.list);
45696                                     }
45697                                 });
45698                             }
45699                             ;
45700                         });
45701                     }
45702                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
45703                     return DirectoryController;
45704                 })();
45705                 directives.DirectoryController = DirectoryController;
45706             })(directives = app.directives || (app.directives = {}));
45707         })(app || (app = {}));
45708         var app;
45709         (function (app) {
45710             var controllers;
45711             (function (controllers) {
45712                 var Execution = (function () {
45713                     function Execution(MyModal, $scope) {
45714                         this.MyModal = MyModal;
45715                         this.$scope = $scope;
45716                         this.commandInfoList = [];
45717                     }
45718                     ;
45719                     Execution.prototype.add = function () {
45720                         this.$scope.$broadcast('close');
45721                         var commandInfoList = this.commandInfoList;
45722                         var commandInstance = this.MyModal.selectCommand();
45723                         commandInstance
45724                             .result
45725                             .then(function (command) {
45726                             commandInfoList.push(new app.declares.CommandInfo(command));
45727                         });
45728                     };
45729                     Execution.prototype.open = function () {
45730                         var result = this.MyModal.open('SelectCommand');
45731                         console.log(result);
45732                     };
45733                     Execution.prototype.remove = function (index, list) {
45734                         list.splice(index, 1);
45735                     };
45736                     Execution.prototype.close = function () {
45737                         console.log("close");
45738                     };
45739                     Execution.$inject = ['MyModal', '$scope'];
45740                     return Execution;
45741                 })();
45742                 controllers.Execution = Execution;
45743             })(controllers = app.controllers || (app.controllers = {}));
45744         })(app || (app = {}));
45745         var app;
45746         (function (app) {
45747             var controllers;
45748             (function (controllers) {
45749                 var Workspace = (function () {
45750                     function Workspace($scope, APIEndPoint, MyModal) {
45751                         this.$scope = $scope;
45752                         this.APIEndPoint = APIEndPoint;
45753                         this.MyModal = MyModal;
45754                         this.directoryList = [];
45755                         var controller = this;
45756                         var directoryList = this.directoryList;
45757                         var o = {
45758                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
45759                             name: '',
45760                             parentId: '',
45761                             fileType: '',
45762                             createdAt: '',
45763                             updatedAt: '',
45764                             path: '/'
45765                         };
45766                         directoryList.push(o);
45767                     }
45768                     Workspace.prototype.addDirectory = function (info, directoryList) {
45769                         directoryList.push(info);
45770                     };
45771                     Workspace.prototype.debug = function () {
45772                         this.MyModal.preview();
45773                     };
45774                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
45775                     return Workspace;
45776                 })();
45777                 controllers.Workspace = Workspace;
45778             })(controllers = app.controllers || (app.controllers = {}));
45779         })(app || (app = {}));
45780         var app;
45781         (function (app) {
45782             var controllers;
45783             (function (controllers) {
45784                 var History = (function () {
45785                     function History($scope) {
45786                         this.page = "History";
45787                     }
45788                     History.$inject = ['$scope'];
45789                     return History;
45790                 })();
45791                 controllers.History = History;
45792             })(controllers = app.controllers || (app.controllers = {}));
45793         })(app || (app = {}));
45794         var app;
45795         (function (app) {
45796             var controllers;
45797             (function (controllers) {
45798                 var SelectCommand = (function () {
45799                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
45800                         this.APIEndPoint = APIEndPoint;
45801                         this.$modalInstance = $modalInstance;
45802                         var controller = this;
45803                         this.APIEndPoint
45804                             .getTags()
45805                             .$promise.then(function (result) {
45806                             controller.tags = result.info;
45807                         });
45808                         this.APIEndPoint
45809                             .getCommands()
45810                             .$promise.then(function (result) {
45811                             controller.commands = result.info;
45812                         });
45813                         this.currentTag = 'all';
45814                     }
45815                     SelectCommand.prototype.changeTag = function (tag) {
45816                         this.currentTag = tag;
45817                     };
45818                     SelectCommand.prototype.selectCommand = function (command) {
45819                         this.$modalInstance.close(command);
45820                     };
45821                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45822                     return SelectCommand;
45823                 })();
45824                 controllers.SelectCommand = SelectCommand;
45825             })(controllers = app.controllers || (app.controllers = {}));
45826         })(app || (app = {}));
45827         var app;
45828         (function (app) {
45829             var controllers;
45830             (function (controllers) {
45831                 var Preview = (function () {
45832                     function Preview($scope, APIEndPoint, $modalInstance) {
45833                         this.APIEndPoint = APIEndPoint;
45834                         this.$modalInstance = $modalInstance;
45835                         var controller = this;
45836                         console.log('preview');
45837                     }
45838                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45839                     return Preview;
45840                 })();
45841                 controllers.Preview = Preview;
45842             })(controllers = app.controllers || (app.controllers = {}));
45843         })(app || (app = {}));
45844         var filters;
45845         (function (filters) {
45846             function Tag() {
45847                 return function (commands, tag) {
45848                     var result = [];
45849                     angular.forEach(commands, function (command) {
45850                         var flag = false;
45851                         angular.forEach(command.tags, function (value) {
45852                             if (tag === value)
45853                                 flag = true;
45854                         });
45855                         if (flag)
45856                             result.push(command);
45857                     });
45858                     return result;
45859                 };
45860             }
45861             filters.Tag = Tag;
45862         })(filters || (filters = {}));
45863         var app;
45864         (function (app) {
45865             'use strict';
45866             var appName = 'zephyr';
45867             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
45868             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
45869                 $urlRouterProvider.otherwise('/execution');
45870                 $locationProvider.html5Mode({
45871                     enabled: true,
45872                     requireBase: false
45873                 });
45874                 $stateProvider
45875                     .state('execution', {
45876                     url: '/execution',
45877                     templateUrl: 'templates/execution.html',
45878                     controller: 'executionController',
45879                     controllerAs: 'c'
45880                 })
45881                     .state('workspace', {
45882                     url: '/workspace',
45883                     templateUrl: 'templates/workspace.html',
45884                     controller: 'workspaceController',
45885                     controllerAs: 'c'
45886                 })
45887                     .state('history', {
45888                     url: '/history',
45889                     templateUrl: 'templates/history.html',
45890                     controller: 'historyController',
45891                     controllerAs: 'c'
45892                 });
45893             });
45894             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
45895             app.zephyr.service('MyModal', app.services.MyModal);
45896             app.zephyr.service('WebSocket', app.services.WebSocket);
45897             app.zephyr.service('Console', app.services.Console);
45898             app.zephyr.filter('Tag', filters.Tag);
45899             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
45900             app.zephyr.controller('previewController', app.controllers.Preview);
45901             app.zephyr.controller('executionController', app.controllers.Execution);
45902             app.zephyr.controller('workspaceController', app.controllers.Workspace);
45903             app.zephyr.controller('historyController', app.controllers.History);
45904             app.zephyr.controller('commandController', app.directives.CommandController);
45905             app.zephyr.controller('optionController', app.directives.OptionController);
45906             app.zephyr.controller('directoryController', app.directives.DirectoryController);
45907             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
45908             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
45909             app.zephyr.directive('command', app.directives.Command.Factory());
45910             app.zephyr.directive('option', app.directives.Option.Factory());
45911             app.zephyr.directive('directory', app.directives.Directory.Factory());
45912         })(app || (app = {}));
45913
45914
45915 /***/ },
45916 /* 15 */
45917 /***/ function(module, exports) {
45918
45919         var app;
45920         (function (app) {
45921             var declares;
45922             (function (declares) {
45923                 var CommandInfo = (function () {
45924                     function CommandInfo(name) {
45925                         this.name = name;
45926                     }
45927                     return CommandInfo;
45928                 })();
45929                 declares.CommandInfo = CommandInfo;
45930             })(declares = app.declares || (app.declares = {}));
45931         })(app || (app = {}));
45932         var app;
45933         (function (app) {
45934             var services;
45935             (function (services) {
45936                 var APIEndPoint = (function () {
45937                     function APIEndPoint($resource, $http) {
45938                         this.$resource = $resource;
45939                         this.$http = $http;
45940                     }
45941                     APIEndPoint.prototype.resource = function (endPoint, data) {
45942                         var customAction = {
45943                             method: 'GET',
45944                             isArray: false
45945                         };
45946                         var execute = {
45947                             method: 'POST',
45948                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
45949                         };
45950                         return this.$resource(endPoint, {}, { execute: execute });
45951                     };
45952                     APIEndPoint.prototype.getOptionControlFile = function (command) {
45953                         var endPoint = '/api/v1/optionControlFile/' + command;
45954                         return this.resource(endPoint, {}).get();
45955                     };
45956                     APIEndPoint.prototype.getFiles = function (fileId) {
45957                         var endPoint = '/api/v1/workspace';
45958                         if (fileId) {
45959                             endPoint += '/' + fileId;
45960                         }
45961                         return this.resource(endPoint, {}).get();
45962                     };
45963                     APIEndPoint.prototype.getDirectories = function () {
45964                         var endPoint = '/api/v1/all/workspace/directory';
45965                         return this.resource(endPoint, {}).get();
45966                     };
45967                     APIEndPoint.prototype.getTags = function () {
45968                         var endPoint = '/api/v1/tagList';
45969                         return this.resource(endPoint, {}).get();
45970                     };
45971                     APIEndPoint.prototype.getCommands = function () {
45972                         var endPoint = '/api/v1/commandList';
45973                         return this.resource(endPoint, {}).get();
45974                     };
45975                     APIEndPoint.prototype.execute = function (data) {
45976                         var endPoint = '/api/v1/execution';
45977                         var fd = new FormData();
45978                         fd.append('data', data);
45979                         return this.$http.post(endPoint, fd, {
45980                             headers: { 'Content-Type': undefined },
45981                             transformRequest: angular.identity
45982                         });
45983                     };
45984                     APIEndPoint.prototype.debug = function () {
45985                         var endPoint = '/api/v1/debug';
45986                         return this.$http.get(endPoint);
45987                     };
45988                     APIEndPoint.prototype.help = function (command) {
45989                         var endPoint = '/api/v1/help/' + command;
45990                         return this.$http.get(endPoint);
45991                     };
45992                     return APIEndPoint;
45993                 })();
45994                 services.APIEndPoint = APIEndPoint;
45995             })(services = app.services || (app.services = {}));
45996         })(app || (app = {}));
45997         var app;
45998         (function (app) {
45999             var services;
46000             (function (services) {
46001                 var MyModal = (function () {
46002                     function MyModal($uibModal) {
46003                         this.$uibModal = $uibModal;
46004                         this.modalOption = {
46005                             backdrop: true,
46006                             controller: null,
46007                             templateUrl: null,
46008                             size: null
46009                         };
46010                     }
46011                     MyModal.prototype.open = function (modalName) {
46012                         if (modalName === 'SelectCommand') {
46013                             this.modalOption.templateUrl = 'templates/select-command.html';
46014                             this.modalOption.size = 'lg';
46015                         }
46016                         return this.$uibModal.open(this.modalOption);
46017                     };
46018                     MyModal.prototype.selectCommand = function () {
46019                         this.modalOption.templateUrl = 'templates/select-command.html';
46020                         this.modalOption.controller = 'selectCommandController';
46021                         this.modalOption.controllerAs = 'c';
46022                         this.modalOption.size = 'lg';
46023                         return this.$uibModal.open(this.modalOption);
46024                     };
46025                     MyModal.prototype.preview = function () {
46026                         this.modalOption.templateUrl = 'templates/preview.html';
46027                         this.modalOption.controller = 'previewController';
46028                         this.modalOption.controllerAs = 'c';
46029                         this.modalOption.size = 'lg';
46030                         return this.$uibModal.open(this.modalOption);
46031                     };
46032                     MyModal.$inject = ['$uibModal'];
46033                     return MyModal;
46034                 })();
46035                 services.MyModal = MyModal;
46036             })(services = app.services || (app.services = {}));
46037         })(app || (app = {}));
46038         var app;
46039         (function (app) {
46040             var services;
46041             (function (services) {
46042                 var WebSocket = (function () {
46043                     function WebSocket($rootScope) {
46044                         this.$rootScope = $rootScope;
46045                         this.socket = io.connect();
46046                     }
46047                     WebSocket.prototype.on = function (eventName, callback) {
46048                         var socket = this.socket;
46049                         var rootScope = this.$rootScope;
46050                         socket.on(eventName, function () {
46051                             var args = arguments;
46052                             rootScope.$apply(function () {
46053                                 callback.apply(socket, args);
46054                             });
46055                         });
46056                     };
46057                     WebSocket.prototype.emit = function (eventName, data, callback) {
46058                         var socket = this.socket;
46059                         var rootScope = this.$rootScope;
46060                         this.socket.emit(eventName, data, function () {
46061                             var args = arguments;
46062                             rootScope.$apply(function () {
46063                                 if (callback)
46064                                     callback.apply(socket, args);
46065                             });
46066                         });
46067                     };
46068                     return WebSocket;
46069                 })();
46070                 services.WebSocket = WebSocket;
46071             })(services = app.services || (app.services = {}));
46072         })(app || (app = {}));
46073         var app;
46074         (function (app) {
46075             var services;
46076             (function (services) {
46077                 var Console = (function () {
46078                     function Console(WebSocket, $rootScope) {
46079                         this.WebSocket = WebSocket;
46080                         this.$rootScope = $rootScope;
46081                         this.WebSocket = WebSocket;
46082                         this.$rootScope = $rootScope;
46083                         this.directiveIDs = [];
46084                         var directiveIDs = this.directiveIDs;
46085                         this.WebSocket.on('console', function (d) {
46086                             var id = d.id;
46087                             var message = d.message;
46088                             if (directiveIDs.indexOf(id) > -1) {
46089                                 $rootScope.$emit(id, message);
46090                             }
46091                         });
46092                     }
46093                     Console.prototype.addDirective = function (id) {
46094                         if (!(this.directiveIDs.indexOf(id) > -1)) {
46095                             this.directiveIDs.push(id);
46096                         }
46097                     };
46098                     Console.prototype.removeDirective = function (id) {
46099                         var i = this.directiveIDs.indexOf(id);
46100                         if (i > -1) {
46101                             this.directiveIDs.splice(i, 1);
46102                         }
46103                     };
46104                     Console.prototype.showIDs = function () {
46105                         console.log(this.directiveIDs);
46106                     };
46107                     return Console;
46108                 })();
46109                 services.Console = Console;
46110             })(services = app.services || (app.services = {}));
46111         })(app || (app = {}));
46112         var app;
46113         (function (app) {
46114             var directives;
46115             (function (directives) {
46116                 var Command = (function () {
46117                     function Command() {
46118                         this.restrict = 'E';
46119                         this.replace = true;
46120                         this.scope = true;
46121                         this.controller = 'commandController';
46122                         this.controllerAs = 'ctrl';
46123                         this.bindToController = {
46124                             index: '=',
46125                             name: '=',
46126                             remove: '&',
46127                             list: '='
46128                         };
46129                         this.templateUrl = 'templates/command.html';
46130                     }
46131                     Command.Factory = function () {
46132                         var directive = function () {
46133                             return new Command();
46134                         };
46135                         directive.$inject = [];
46136                         return directive;
46137                     };
46138                     return Command;
46139                 })();
46140                 directives.Command = Command;
46141                 var CommandController = (function () {
46142                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
46143                         this.APIEndPoint = APIEndPoint;
46144                         this.$scope = $scope;
46145                         this.MyModal = MyModal;
46146                         this.WebSocket = WebSocket;
46147                         this.$window = $window;
46148                         this.$rootScope = $rootScope;
46149                         this.Console = Console;
46150                         var controller = this;
46151                         this.APIEndPoint
46152                             .getOptionControlFile(this.name)
46153                             .$promise
46154                             .then(function (result) {
46155                             controller.options = result.info;
46156                         });
46157                         this.APIEndPoint
46158                             .getDirectories()
46159                             .$promise
46160                             .then(function (result) {
46161                             controller.dirs = result.info;
46162                         });
46163                         this.heading = "[" + this.index + "]: dcdFilePrint";
46164                         this.isOpen = true;
46165                         this.$scope.$on('close', function () {
46166                             controller.isOpen = false;
46167                         });
46168                         function guid() {
46169                             function s4() {
46170                                 return Math.floor((1 + Math.random()) * 0x10000)
46171                                     .toString(16)
46172                                     .substring(1);
46173                             }
46174                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
46175                                 s4() + '-' + s4() + s4() + s4();
46176                         }
46177                         this.uuid = guid();
46178                         this.Console.addDirective(this.uuid);
46179                         this.Console.showIDs();
46180                     }
46181                     CommandController.prototype.submit = function () {
46182                         var opt = [];
46183                         angular.forEach(this.options, function (option) {
46184                             var obj = {
46185                                 name: option.option,
46186                                 arguments: []
46187                             };
46188                             angular.forEach(option.arg, function (arg) {
46189                                 if (arg.input) {
46190                                     if (typeof arg.input === 'object') {
46191                                         obj.arguments.push(arg.input.name);
46192                                     }
46193                                     else {
46194                                         obj.arguments.push(arg.input);
46195                                     }
46196                                 }
46197                             });
46198                             if (obj.arguments.length > 0) {
46199                                 opt.push(obj);
46200                             }
46201                         });
46202                         var execObj = {
46203                             command: this.name,
46204                             workspace: this.workspace.fileId,
46205                             options: opt
46206                         };
46207                         this.APIEndPoint
46208                             .execute(JSON.stringify(execObj))
46209                             .then(function (result) {
46210                             console.log(result);
46211                         });
46212                     };
46213                     CommandController.prototype.removeMySelf = function (index) {
46214                         this.$scope.$destroy();
46215                         this.Console.removeDirective(this.uuid);
46216                         this.remove()(index, this.list);
46217                         this.Console.showIDs();
46218                     };
46219                     CommandController.prototype.reloadFiles = function () {
46220                         var _this = this;
46221                         var fileId = this.workspace.fileId;
46222                         this.APIEndPoint
46223                             .getFiles(fileId)
46224                             .$promise
46225                             .then(function (result) {
46226                             var status = result.status;
46227                             if (status === 'success') {
46228                                 _this.files = result.info;
46229                             }
46230                             else {
46231                                 console.log(result.message);
46232                             }
46233                         });
46234                     };
46235                     CommandController.prototype.debug = function () {
46236                         var div = angular.element(this.$window.document).find("div");
46237                         var consoleTag;
46238                         var parametersTag;
46239                         angular.forEach(div, function (v) {
46240                             if (v.className === "panel-body console") {
46241                                 consoleTag = v;
46242                             }
46243                             else if (v.className === "row parameters-console") {
46244                                 parametersTag = v;
46245                             }
46246                         });
46247                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
46248                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
46249                         consoleTag.style.height = consoleHeight;
46250                         consoleTag.style.width = consoleWidth;
46251                     };
46252                     CommandController.prototype.help = function () {
46253                         this.APIEndPoint
46254                             .help(this.name)
46255                             .then(function (result) {
46256                             console.log(result);
46257                         });
46258                     };
46259                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
46260                     return CommandController;
46261                 })();
46262                 directives.CommandController = CommandController;
46263             })(directives = app.directives || (app.directives = {}));
46264         })(app || (app = {}));
46265         var app;
46266         (function (app) {
46267             var directives;
46268             (function (directives) {
46269                 var HeaderMenu = (function () {
46270                     function HeaderMenu() {
46271                         this.restrict = 'E';
46272                         this.replace = true;
46273                         this.templateUrl = 'templates/header-menu.html';
46274                         this.controller = 'HeaderMenuController';
46275                         this.controllerAs = 'hmc';
46276                         this.scope = true;
46277                     }
46278                     HeaderMenu.Factory = function () {
46279                         var directive = function () {
46280                             return new HeaderMenu();
46281                         };
46282                         return directive;
46283                     };
46284                     return HeaderMenu;
46285                 })();
46286                 directives.HeaderMenu = HeaderMenu;
46287                 var HeaderMenuController = (function () {
46288                     function HeaderMenuController($state) {
46289                         this.$state = $state;
46290                         this.isExecution = this.$state.current.name === 'execution';
46291                         this.isWorkspace = this.$state.current.name === 'workspace';
46292                         this.isHistory = this.$state.current.name === 'history';
46293                     }
46294                     HeaderMenuController.prototype.transit = function (state) {
46295                         this.$state.go(state);
46296                     };
46297                     HeaderMenuController.$inject = ['$state'];
46298                     return HeaderMenuController;
46299                 })();
46300                 directives.HeaderMenuController = HeaderMenuController;
46301             })(directives = app.directives || (app.directives = {}));
46302         })(app || (app = {}));
46303         var app;
46304         (function (app) {
46305             var directives;
46306             (function (directives) {
46307                 var Option = (function () {
46308                     function Option() {
46309                         this.restrict = 'E';
46310                         this.replace = true;
46311                         this.controller = 'optionController';
46312                         this.bindToController = {
46313                             info: '=',
46314                             files: '='
46315                         };
46316                         this.scope = true;
46317                         this.templateUrl = 'templates/option.html';
46318                         this.controllerAs = 'ctrl';
46319                     }
46320                     Option.Factory = function () {
46321                         var directive = function () {
46322                             return new Option();
46323                         };
46324                         directive.$inject = [];
46325                         return directive;
46326                     };
46327                     return Option;
46328                 })();
46329                 directives.Option = Option;
46330                 var OptionController = (function () {
46331                     function OptionController() {
46332                         var controller = this;
46333                         angular.forEach(controller.info.arg, function (arg) {
46334                             if (arg.initialValue) {
46335                                 if (arg.formType === 'number') {
46336                                     arg.input = parseInt(arg.initialValue);
46337                                 }
46338                                 else {
46339                                     arg.input = arg.initialValue;
46340                                 }
46341                             }
46342                         });
46343                     }
46344                     OptionController.$inject = [];
46345                     return OptionController;
46346                 })();
46347                 directives.OptionController = OptionController;
46348             })(directives = app.directives || (app.directives = {}));
46349         })(app || (app = {}));
46350         var app;
46351         (function (app) {
46352             var directives;
46353             (function (directives) {
46354                 var Directory = (function () {
46355                     function Directory() {
46356                         this.restrict = 'E';
46357                         this.replace = true;
46358                         this.controller = 'directoryController';
46359                         this.controllerAs = 'ctrl';
46360                         this.bindToController = {
46361                             info: '=',
46362                             add: '&',
46363                             list: '=',
46364                             files: '='
46365                         };
46366                         this.templateUrl = 'templates/directory.html';
46367                     }
46368                     Directory.Factory = function () {
46369                         var directive = function () {
46370                             return new Directory();
46371                         };
46372                         return directive;
46373                     };
46374                     return Directory;
46375                 })();
46376                 directives.Directory = Directory;
46377                 var DirectoryController = (function () {
46378                     function DirectoryController(APIEndPoint, $scope) {
46379                         this.APIEndPoint = APIEndPoint;
46380                         this.$scope = $scope;
46381                         var controller = this;
46382                         this.APIEndPoint
46383                             .getFiles(this.info.fileId)
46384                             .$promise
46385                             .then(function (result) {
46386                             if (result.status === 'success') {
46387                                 controller.files = result.info;
46388                                 angular.forEach(result.info, function (file) {
46389                                     if (file.fileType === '0') {
46390                                         var o = file;
46391                                         if (controller.info.path === '/') {
46392                                             o.path = '/' + file.name;
46393                                         }
46394                                         else {
46395                                             o.path = controller.info.path + '/' + file.name;
46396                                         }
46397                                         controller.add()(o, controller.list);
46398                                     }
46399                                 });
46400                             }
46401                             ;
46402                         });
46403                     }
46404                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
46405                     return DirectoryController;
46406                 })();
46407                 directives.DirectoryController = DirectoryController;
46408             })(directives = app.directives || (app.directives = {}));
46409         })(app || (app = {}));
46410         var app;
46411         (function (app) {
46412             var controllers;
46413             (function (controllers) {
46414                 var Execution = (function () {
46415                     function Execution(MyModal, $scope) {
46416                         this.MyModal = MyModal;
46417                         this.$scope = $scope;
46418                         this.commandInfoList = [];
46419                     }
46420                     ;
46421                     Execution.prototype.add = function () {
46422                         this.$scope.$broadcast('close');
46423                         var commandInfoList = this.commandInfoList;
46424                         var commandInstance = this.MyModal.selectCommand();
46425                         commandInstance
46426                             .result
46427                             .then(function (command) {
46428                             commandInfoList.push(new app.declares.CommandInfo(command));
46429                         });
46430                     };
46431                     Execution.prototype.open = function () {
46432                         var result = this.MyModal.open('SelectCommand');
46433                         console.log(result);
46434                     };
46435                     Execution.prototype.remove = function (index, list) {
46436                         list.splice(index, 1);
46437                     };
46438                     Execution.prototype.close = function () {
46439                         console.log("close");
46440                     };
46441                     Execution.$inject = ['MyModal', '$scope'];
46442                     return Execution;
46443                 })();
46444                 controllers.Execution = Execution;
46445             })(controllers = app.controllers || (app.controllers = {}));
46446         })(app || (app = {}));
46447         var app;
46448         (function (app) {
46449             var controllers;
46450             (function (controllers) {
46451                 var Workspace = (function () {
46452                     function Workspace($scope, APIEndPoint, MyModal) {
46453                         this.$scope = $scope;
46454                         this.APIEndPoint = APIEndPoint;
46455                         this.MyModal = MyModal;
46456                         this.directoryList = [];
46457                         var controller = this;
46458                         var directoryList = this.directoryList;
46459                         var o = {
46460                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
46461                             name: '',
46462                             parentId: '',
46463                             fileType: '',
46464                             createdAt: '',
46465                             updatedAt: '',
46466                             path: '/'
46467                         };
46468                         directoryList.push(o);
46469                     }
46470                     Workspace.prototype.addDirectory = function (info, directoryList) {
46471                         directoryList.push(info);
46472                     };
46473                     Workspace.prototype.debug = function () {
46474                         this.MyModal.preview();
46475                     };
46476                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
46477                     return Workspace;
46478                 })();
46479                 controllers.Workspace = Workspace;
46480             })(controllers = app.controllers || (app.controllers = {}));
46481         })(app || (app = {}));
46482         var app;
46483         (function (app) {
46484             var controllers;
46485             (function (controllers) {
46486                 var History = (function () {
46487                     function History($scope) {
46488                         this.page = "History";
46489                     }
46490                     History.$inject = ['$scope'];
46491                     return History;
46492                 })();
46493                 controllers.History = History;
46494             })(controllers = app.controllers || (app.controllers = {}));
46495         })(app || (app = {}));
46496         var app;
46497         (function (app) {
46498             var controllers;
46499             (function (controllers) {
46500                 var SelectCommand = (function () {
46501                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
46502                         this.APIEndPoint = APIEndPoint;
46503                         this.$modalInstance = $modalInstance;
46504                         var controller = this;
46505                         this.APIEndPoint
46506                             .getTags()
46507                             .$promise.then(function (result) {
46508                             controller.tags = result.info;
46509                         });
46510                         this.APIEndPoint
46511                             .getCommands()
46512                             .$promise.then(function (result) {
46513                             controller.commands = result.info;
46514                         });
46515                         this.currentTag = 'all';
46516                     }
46517                     SelectCommand.prototype.changeTag = function (tag) {
46518                         this.currentTag = tag;
46519                     };
46520                     SelectCommand.prototype.selectCommand = function (command) {
46521                         this.$modalInstance.close(command);
46522                     };
46523                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46524                     return SelectCommand;
46525                 })();
46526                 controllers.SelectCommand = SelectCommand;
46527             })(controllers = app.controllers || (app.controllers = {}));
46528         })(app || (app = {}));
46529         var app;
46530         (function (app) {
46531             var controllers;
46532             (function (controllers) {
46533                 var Preview = (function () {
46534                     function Preview($scope, APIEndPoint, $modalInstance) {
46535                         this.APIEndPoint = APIEndPoint;
46536                         this.$modalInstance = $modalInstance;
46537                         var controller = this;
46538                         console.log('preview');
46539                     }
46540                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46541                     return Preview;
46542                 })();
46543                 controllers.Preview = Preview;
46544             })(controllers = app.controllers || (app.controllers = {}));
46545         })(app || (app = {}));
46546         var filters;
46547         (function (filters) {
46548             function Tag() {
46549                 return function (commands, tag) {
46550                     var result = [];
46551                     angular.forEach(commands, function (command) {
46552                         var flag = false;
46553                         angular.forEach(command.tags, function (value) {
46554                             if (tag === value)
46555                                 flag = true;
46556                         });
46557                         if (flag)
46558                             result.push(command);
46559                     });
46560                     return result;
46561                 };
46562             }
46563             filters.Tag = Tag;
46564         })(filters || (filters = {}));
46565         var app;
46566         (function (app) {
46567             'use strict';
46568             var appName = 'zephyr';
46569             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
46570             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
46571                 $urlRouterProvider.otherwise('/execution');
46572                 $locationProvider.html5Mode({
46573                     enabled: true,
46574                     requireBase: false
46575                 });
46576                 $stateProvider
46577                     .state('execution', {
46578                     url: '/execution',
46579                     templateUrl: 'templates/execution.html',
46580                     controller: 'executionController',
46581                     controllerAs: 'c'
46582                 })
46583                     .state('workspace', {
46584                     url: '/workspace',
46585                     templateUrl: 'templates/workspace.html',
46586                     controller: 'workspaceController',
46587                     controllerAs: 'c'
46588                 })
46589                     .state('history', {
46590                     url: '/history',
46591                     templateUrl: 'templates/history.html',
46592                     controller: 'historyController',
46593                     controllerAs: 'c'
46594                 });
46595             });
46596             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
46597             app.zephyr.service('MyModal', app.services.MyModal);
46598             app.zephyr.service('WebSocket', app.services.WebSocket);
46599             app.zephyr.service('Console', app.services.Console);
46600             app.zephyr.filter('Tag', filters.Tag);
46601             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
46602             app.zephyr.controller('previewController', app.controllers.Preview);
46603             app.zephyr.controller('executionController', app.controllers.Execution);
46604             app.zephyr.controller('workspaceController', app.controllers.Workspace);
46605             app.zephyr.controller('historyController', app.controllers.History);
46606             app.zephyr.controller('commandController', app.directives.CommandController);
46607             app.zephyr.controller('optionController', app.directives.OptionController);
46608             app.zephyr.controller('directoryController', app.directives.DirectoryController);
46609             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
46610             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
46611             app.zephyr.directive('command', app.directives.Command.Factory());
46612             app.zephyr.directive('option', app.directives.Option.Factory());
46613             app.zephyr.directive('directory', app.directives.Directory.Factory());
46614         })(app || (app = {}));
46615
46616
46617 /***/ },
46618 /* 16 */
46619 /***/ function(module, exports) {
46620
46621         var app;
46622         (function (app) {
46623             var declares;
46624             (function (declares) {
46625                 var CommandInfo = (function () {
46626                     function CommandInfo(name) {
46627                         this.name = name;
46628                     }
46629                     return CommandInfo;
46630                 })();
46631                 declares.CommandInfo = CommandInfo;
46632             })(declares = app.declares || (app.declares = {}));
46633         })(app || (app = {}));
46634         var app;
46635         (function (app) {
46636             var services;
46637             (function (services) {
46638                 var APIEndPoint = (function () {
46639                     function APIEndPoint($resource, $http) {
46640                         this.$resource = $resource;
46641                         this.$http = $http;
46642                     }
46643                     APIEndPoint.prototype.resource = function (endPoint, data) {
46644                         var customAction = {
46645                             method: 'GET',
46646                             isArray: false
46647                         };
46648                         var execute = {
46649                             method: 'POST',
46650                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
46651                         };
46652                         return this.$resource(endPoint, {}, { execute: execute });
46653                     };
46654                     APIEndPoint.prototype.getOptionControlFile = function (command) {
46655                         var endPoint = '/api/v1/optionControlFile/' + command;
46656                         return this.resource(endPoint, {}).get();
46657                     };
46658                     APIEndPoint.prototype.getFiles = function (fileId) {
46659                         var endPoint = '/api/v1/workspace';
46660                         if (fileId) {
46661                             endPoint += '/' + fileId;
46662                         }
46663                         return this.resource(endPoint, {}).get();
46664                     };
46665                     APIEndPoint.prototype.getDirectories = function () {
46666                         var endPoint = '/api/v1/all/workspace/directory';
46667                         return this.resource(endPoint, {}).get();
46668                     };
46669                     APIEndPoint.prototype.getTags = function () {
46670                         var endPoint = '/api/v1/tagList';
46671                         return this.resource(endPoint, {}).get();
46672                     };
46673                     APIEndPoint.prototype.getCommands = function () {
46674                         var endPoint = '/api/v1/commandList';
46675                         return this.resource(endPoint, {}).get();
46676                     };
46677                     APIEndPoint.prototype.execute = function (data) {
46678                         var endPoint = '/api/v1/execution';
46679                         var fd = new FormData();
46680                         fd.append('data', data);
46681                         return this.$http.post(endPoint, fd, {
46682                             headers: { 'Content-Type': undefined },
46683                             transformRequest: angular.identity
46684                         });
46685                     };
46686                     APIEndPoint.prototype.debug = function () {
46687                         var endPoint = '/api/v1/debug';
46688                         return this.$http.get(endPoint);
46689                     };
46690                     APIEndPoint.prototype.help = function (command) {
46691                         var endPoint = '/api/v1/help/' + command;
46692                         return this.$http.get(endPoint);
46693                     };
46694                     return APIEndPoint;
46695                 })();
46696                 services.APIEndPoint = APIEndPoint;
46697             })(services = app.services || (app.services = {}));
46698         })(app || (app = {}));
46699         var app;
46700         (function (app) {
46701             var services;
46702             (function (services) {
46703                 var MyModal = (function () {
46704                     function MyModal($uibModal) {
46705                         this.$uibModal = $uibModal;
46706                         this.modalOption = {
46707                             backdrop: true,
46708                             controller: null,
46709                             templateUrl: null,
46710                             size: null
46711                         };
46712                     }
46713                     MyModal.prototype.open = function (modalName) {
46714                         if (modalName === 'SelectCommand') {
46715                             this.modalOption.templateUrl = 'templates/select-command.html';
46716                             this.modalOption.size = 'lg';
46717                         }
46718                         return this.$uibModal.open(this.modalOption);
46719                     };
46720                     MyModal.prototype.selectCommand = function () {
46721                         this.modalOption.templateUrl = 'templates/select-command.html';
46722                         this.modalOption.controller = 'selectCommandController';
46723                         this.modalOption.controllerAs = 'c';
46724                         this.modalOption.size = 'lg';
46725                         return this.$uibModal.open(this.modalOption);
46726                     };
46727                     MyModal.prototype.preview = function () {
46728                         this.modalOption.templateUrl = 'templates/preview.html';
46729                         this.modalOption.controller = 'previewController';
46730                         this.modalOption.controllerAs = 'c';
46731                         this.modalOption.size = 'lg';
46732                         return this.$uibModal.open(this.modalOption);
46733                     };
46734                     MyModal.$inject = ['$uibModal'];
46735                     return MyModal;
46736                 })();
46737                 services.MyModal = MyModal;
46738             })(services = app.services || (app.services = {}));
46739         })(app || (app = {}));
46740         var app;
46741         (function (app) {
46742             var services;
46743             (function (services) {
46744                 var WebSocket = (function () {
46745                     function WebSocket($rootScope) {
46746                         this.$rootScope = $rootScope;
46747                         this.socket = io.connect();
46748                     }
46749                     WebSocket.prototype.on = function (eventName, callback) {
46750                         var socket = this.socket;
46751                         var rootScope = this.$rootScope;
46752                         socket.on(eventName, function () {
46753                             var args = arguments;
46754                             rootScope.$apply(function () {
46755                                 callback.apply(socket, args);
46756                             });
46757                         });
46758                     };
46759                     WebSocket.prototype.emit = function (eventName, data, callback) {
46760                         var socket = this.socket;
46761                         var rootScope = this.$rootScope;
46762                         this.socket.emit(eventName, data, function () {
46763                             var args = arguments;
46764                             rootScope.$apply(function () {
46765                                 if (callback)
46766                                     callback.apply(socket, args);
46767                             });
46768                         });
46769                     };
46770                     return WebSocket;
46771                 })();
46772                 services.WebSocket = WebSocket;
46773             })(services = app.services || (app.services = {}));
46774         })(app || (app = {}));
46775         var app;
46776         (function (app) {
46777             var services;
46778             (function (services) {
46779                 var Console = (function () {
46780                     function Console(WebSocket, $rootScope) {
46781                         this.WebSocket = WebSocket;
46782                         this.$rootScope = $rootScope;
46783                         this.WebSocket = WebSocket;
46784                         this.$rootScope = $rootScope;
46785                         this.directiveIDs = [];
46786                         var directiveIDs = this.directiveIDs;
46787                         this.WebSocket.on('console', function (d) {
46788                             var id = d.id;
46789                             var message = d.message;
46790                             if (directiveIDs.indexOf(id) > -1) {
46791                                 $rootScope.$emit(id, message);
46792                             }
46793                         });
46794                     }
46795                     Console.prototype.addDirective = function (id) {
46796                         if (!(this.directiveIDs.indexOf(id) > -1)) {
46797                             this.directiveIDs.push(id);
46798                         }
46799                     };
46800                     Console.prototype.removeDirective = function (id) {
46801                         var i = this.directiveIDs.indexOf(id);
46802                         if (i > -1) {
46803                             this.directiveIDs.splice(i, 1);
46804                         }
46805                     };
46806                     Console.prototype.showIDs = function () {
46807                         console.log(this.directiveIDs);
46808                     };
46809                     return Console;
46810                 })();
46811                 services.Console = Console;
46812             })(services = app.services || (app.services = {}));
46813         })(app || (app = {}));
46814         var app;
46815         (function (app) {
46816             var directives;
46817             (function (directives) {
46818                 var Command = (function () {
46819                     function Command() {
46820                         this.restrict = 'E';
46821                         this.replace = true;
46822                         this.scope = true;
46823                         this.controller = 'commandController';
46824                         this.controllerAs = 'ctrl';
46825                         this.bindToController = {
46826                             index: '=',
46827                             name: '=',
46828                             remove: '&',
46829                             list: '='
46830                         };
46831                         this.templateUrl = 'templates/command.html';
46832                     }
46833                     Command.Factory = function () {
46834                         var directive = function () {
46835                             return new Command();
46836                         };
46837                         directive.$inject = [];
46838                         return directive;
46839                     };
46840                     return Command;
46841                 })();
46842                 directives.Command = Command;
46843                 var CommandController = (function () {
46844                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
46845                         this.APIEndPoint = APIEndPoint;
46846                         this.$scope = $scope;
46847                         this.MyModal = MyModal;
46848                         this.WebSocket = WebSocket;
46849                         this.$window = $window;
46850                         this.$rootScope = $rootScope;
46851                         this.Console = Console;
46852                         var controller = this;
46853                         this.APIEndPoint
46854                             .getOptionControlFile(this.name)
46855                             .$promise
46856                             .then(function (result) {
46857                             controller.options = result.info;
46858                         });
46859                         this.APIEndPoint
46860                             .getDirectories()
46861                             .$promise
46862                             .then(function (result) {
46863                             controller.dirs = result.info;
46864                         });
46865                         this.heading = "[" + this.index + "]: dcdFilePrint";
46866                         this.isOpen = true;
46867                         this.$scope.$on('close', function () {
46868                             controller.isOpen = false;
46869                         });
46870                         function guid() {
46871                             function s4() {
46872                                 return Math.floor((1 + Math.random()) * 0x10000)
46873                                     .toString(16)
46874                                     .substring(1);
46875                             }
46876                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
46877                                 s4() + '-' + s4() + s4() + s4();
46878                         }
46879                         this.uuid = guid();
46880                         this.Console.addDirective(this.uuid);
46881                         this.Console.showIDs();
46882                     }
46883                     CommandController.prototype.submit = function () {
46884                         var opt = [];
46885                         angular.forEach(this.options, function (option) {
46886                             var obj = {
46887                                 name: option.option,
46888                                 arguments: []
46889                             };
46890                             angular.forEach(option.arg, function (arg) {
46891                                 if (arg.input) {
46892                                     if (typeof arg.input === 'object') {
46893                                         obj.arguments.push(arg.input.name);
46894                                     }
46895                                     else {
46896                                         obj.arguments.push(arg.input);
46897                                     }
46898                                 }
46899                             });
46900                             if (obj.arguments.length > 0) {
46901                                 opt.push(obj);
46902                             }
46903                         });
46904                         var execObj = {
46905                             command: this.name,
46906                             workspace: this.workspace.fileId,
46907                             options: opt
46908                         };
46909                         this.APIEndPoint
46910                             .execute(JSON.stringify(execObj))
46911                             .then(function (result) {
46912                             console.log(result);
46913                         });
46914                     };
46915                     CommandController.prototype.removeMySelf = function (index) {
46916                         this.$scope.$destroy();
46917                         this.Console.removeDirective(this.uuid);
46918                         this.remove()(index, this.list);
46919                         this.Console.showIDs();
46920                     };
46921                     CommandController.prototype.reloadFiles = function () {
46922                         var _this = this;
46923                         var fileId = this.workspace.fileId;
46924                         this.APIEndPoint
46925                             .getFiles(fileId)
46926                             .$promise
46927                             .then(function (result) {
46928                             var status = result.status;
46929                             if (status === 'success') {
46930                                 _this.files = result.info;
46931                             }
46932                             else {
46933                                 console.log(result.message);
46934                             }
46935                         });
46936                     };
46937                     CommandController.prototype.debug = function () {
46938                         var div = angular.element(this.$window.document).find("div");
46939                         var consoleTag;
46940                         var parametersTag;
46941                         angular.forEach(div, function (v) {
46942                             if (v.className === "panel-body console") {
46943                                 consoleTag = v;
46944                             }
46945                             else if (v.className === "row parameters-console") {
46946                                 parametersTag = v;
46947                             }
46948                         });
46949                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
46950                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
46951                         consoleTag.style.height = consoleHeight;
46952                         consoleTag.style.width = consoleWidth;
46953                     };
46954                     CommandController.prototype.help = function () {
46955                         this.APIEndPoint
46956                             .help(this.name)
46957                             .then(function (result) {
46958                             console.log(result);
46959                         });
46960                     };
46961                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
46962                     return CommandController;
46963                 })();
46964                 directives.CommandController = CommandController;
46965             })(directives = app.directives || (app.directives = {}));
46966         })(app || (app = {}));
46967         var app;
46968         (function (app) {
46969             var directives;
46970             (function (directives) {
46971                 var HeaderMenu = (function () {
46972                     function HeaderMenu() {
46973                         this.restrict = 'E';
46974                         this.replace = true;
46975                         this.templateUrl = 'templates/header-menu.html';
46976                         this.controller = 'HeaderMenuController';
46977                         this.controllerAs = 'hmc';
46978                         this.scope = true;
46979                     }
46980                     HeaderMenu.Factory = function () {
46981                         var directive = function () {
46982                             return new HeaderMenu();
46983                         };
46984                         return directive;
46985                     };
46986                     return HeaderMenu;
46987                 })();
46988                 directives.HeaderMenu = HeaderMenu;
46989                 var HeaderMenuController = (function () {
46990                     function HeaderMenuController($state) {
46991                         this.$state = $state;
46992                         this.isExecution = this.$state.current.name === 'execution';
46993                         this.isWorkspace = this.$state.current.name === 'workspace';
46994                         this.isHistory = this.$state.current.name === 'history';
46995                     }
46996                     HeaderMenuController.prototype.transit = function (state) {
46997                         this.$state.go(state);
46998                     };
46999                     HeaderMenuController.$inject = ['$state'];
47000                     return HeaderMenuController;
47001                 })();
47002                 directives.HeaderMenuController = HeaderMenuController;
47003             })(directives = app.directives || (app.directives = {}));
47004         })(app || (app = {}));
47005         var app;
47006         (function (app) {
47007             var directives;
47008             (function (directives) {
47009                 var Option = (function () {
47010                     function Option() {
47011                         this.restrict = 'E';
47012                         this.replace = true;
47013                         this.controller = 'optionController';
47014                         this.bindToController = {
47015                             info: '=',
47016                             files: '='
47017                         };
47018                         this.scope = true;
47019                         this.templateUrl = 'templates/option.html';
47020                         this.controllerAs = 'ctrl';
47021                     }
47022                     Option.Factory = function () {
47023                         var directive = function () {
47024                             return new Option();
47025                         };
47026                         directive.$inject = [];
47027                         return directive;
47028                     };
47029                     return Option;
47030                 })();
47031                 directives.Option = Option;
47032                 var OptionController = (function () {
47033                     function OptionController() {
47034                         var controller = this;
47035                         angular.forEach(controller.info.arg, function (arg) {
47036                             if (arg.initialValue) {
47037                                 if (arg.formType === 'number') {
47038                                     arg.input = parseInt(arg.initialValue);
47039                                 }
47040                                 else {
47041                                     arg.input = arg.initialValue;
47042                                 }
47043                             }
47044                         });
47045                     }
47046                     OptionController.$inject = [];
47047                     return OptionController;
47048                 })();
47049                 directives.OptionController = OptionController;
47050             })(directives = app.directives || (app.directives = {}));
47051         })(app || (app = {}));
47052         var app;
47053         (function (app) {
47054             var directives;
47055             (function (directives) {
47056                 var Directory = (function () {
47057                     function Directory() {
47058                         this.restrict = 'E';
47059                         this.replace = true;
47060                         this.controller = 'directoryController';
47061                         this.controllerAs = 'ctrl';
47062                         this.bindToController = {
47063                             info: '=',
47064                             add: '&',
47065                             list: '=',
47066                             files: '='
47067                         };
47068                         this.templateUrl = 'templates/directory.html';
47069                     }
47070                     Directory.Factory = function () {
47071                         var directive = function () {
47072                             return new Directory();
47073                         };
47074                         return directive;
47075                     };
47076                     return Directory;
47077                 })();
47078                 directives.Directory = Directory;
47079                 var DirectoryController = (function () {
47080                     function DirectoryController(APIEndPoint, $scope) {
47081                         this.APIEndPoint = APIEndPoint;
47082                         this.$scope = $scope;
47083                         var controller = this;
47084                         this.APIEndPoint
47085                             .getFiles(this.info.fileId)
47086                             .$promise
47087                             .then(function (result) {
47088                             if (result.status === 'success') {
47089                                 controller.files = result.info;
47090                                 angular.forEach(result.info, function (file) {
47091                                     if (file.fileType === '0') {
47092                                         var o = file;
47093                                         if (controller.info.path === '/') {
47094                                             o.path = '/' + file.name;
47095                                         }
47096                                         else {
47097                                             o.path = controller.info.path + '/' + file.name;
47098                                         }
47099                                         controller.add()(o, controller.list);
47100                                     }
47101                                 });
47102                             }
47103                             ;
47104                         });
47105                     }
47106                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
47107                     return DirectoryController;
47108                 })();
47109                 directives.DirectoryController = DirectoryController;
47110             })(directives = app.directives || (app.directives = {}));
47111         })(app || (app = {}));
47112         var app;
47113         (function (app) {
47114             var controllers;
47115             (function (controllers) {
47116                 var Execution = (function () {
47117                     function Execution(MyModal, $scope) {
47118                         this.MyModal = MyModal;
47119                         this.$scope = $scope;
47120                         this.commandInfoList = [];
47121                     }
47122                     ;
47123                     Execution.prototype.add = function () {
47124                         this.$scope.$broadcast('close');
47125                         var commandInfoList = this.commandInfoList;
47126                         var commandInstance = this.MyModal.selectCommand();
47127                         commandInstance
47128                             .result
47129                             .then(function (command) {
47130                             commandInfoList.push(new app.declares.CommandInfo(command));
47131                         });
47132                     };
47133                     Execution.prototype.open = function () {
47134                         var result = this.MyModal.open('SelectCommand');
47135                         console.log(result);
47136                     };
47137                     Execution.prototype.remove = function (index, list) {
47138                         list.splice(index, 1);
47139                     };
47140                     Execution.prototype.close = function () {
47141                         console.log("close");
47142                     };
47143                     Execution.$inject = ['MyModal', '$scope'];
47144                     return Execution;
47145                 })();
47146                 controllers.Execution = Execution;
47147             })(controllers = app.controllers || (app.controllers = {}));
47148         })(app || (app = {}));
47149         var app;
47150         (function (app) {
47151             var controllers;
47152             (function (controllers) {
47153                 var Workspace = (function () {
47154                     function Workspace($scope, APIEndPoint, MyModal) {
47155                         this.$scope = $scope;
47156                         this.APIEndPoint = APIEndPoint;
47157                         this.MyModal = MyModal;
47158                         this.directoryList = [];
47159                         var controller = this;
47160                         var directoryList = this.directoryList;
47161                         var o = {
47162                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
47163                             name: '',
47164                             parentId: '',
47165                             fileType: '',
47166                             createdAt: '',
47167                             updatedAt: '',
47168                             path: '/'
47169                         };
47170                         directoryList.push(o);
47171                     }
47172                     Workspace.prototype.addDirectory = function (info, directoryList) {
47173                         directoryList.push(info);
47174                     };
47175                     Workspace.prototype.debug = function () {
47176                         this.MyModal.preview();
47177                     };
47178                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
47179                     return Workspace;
47180                 })();
47181                 controllers.Workspace = Workspace;
47182             })(controllers = app.controllers || (app.controllers = {}));
47183         })(app || (app = {}));
47184         var app;
47185         (function (app) {
47186             var controllers;
47187             (function (controllers) {
47188                 var History = (function () {
47189                     function History($scope) {
47190                         this.page = "History";
47191                     }
47192                     History.$inject = ['$scope'];
47193                     return History;
47194                 })();
47195                 controllers.History = History;
47196             })(controllers = app.controllers || (app.controllers = {}));
47197         })(app || (app = {}));
47198         var app;
47199         (function (app) {
47200             var controllers;
47201             (function (controllers) {
47202                 var SelectCommand = (function () {
47203                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
47204                         this.APIEndPoint = APIEndPoint;
47205                         this.$modalInstance = $modalInstance;
47206                         var controller = this;
47207                         this.APIEndPoint
47208                             .getTags()
47209                             .$promise.then(function (result) {
47210                             controller.tags = result.info;
47211                         });
47212                         this.APIEndPoint
47213                             .getCommands()
47214                             .$promise.then(function (result) {
47215                             controller.commands = result.info;
47216                         });
47217                         this.currentTag = 'all';
47218                     }
47219                     SelectCommand.prototype.changeTag = function (tag) {
47220                         this.currentTag = tag;
47221                     };
47222                     SelectCommand.prototype.selectCommand = function (command) {
47223                         this.$modalInstance.close(command);
47224                     };
47225                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47226                     return SelectCommand;
47227                 })();
47228                 controllers.SelectCommand = SelectCommand;
47229             })(controllers = app.controllers || (app.controllers = {}));
47230         })(app || (app = {}));
47231         var app;
47232         (function (app) {
47233             var controllers;
47234             (function (controllers) {
47235                 var Preview = (function () {
47236                     function Preview($scope, APIEndPoint, $modalInstance) {
47237                         this.APIEndPoint = APIEndPoint;
47238                         this.$modalInstance = $modalInstance;
47239                         var controller = this;
47240                         console.log('preview');
47241                     }
47242                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47243                     return Preview;
47244                 })();
47245                 controllers.Preview = Preview;
47246             })(controllers = app.controllers || (app.controllers = {}));
47247         })(app || (app = {}));
47248         var filters;
47249         (function (filters) {
47250             function Tag() {
47251                 return function (commands, tag) {
47252                     var result = [];
47253                     angular.forEach(commands, function (command) {
47254                         var flag = false;
47255                         angular.forEach(command.tags, function (value) {
47256                             if (tag === value)
47257                                 flag = true;
47258                         });
47259                         if (flag)
47260                             result.push(command);
47261                     });
47262                     return result;
47263                 };
47264             }
47265             filters.Tag = Tag;
47266         })(filters || (filters = {}));
47267         var app;
47268         (function (app) {
47269             'use strict';
47270             var appName = 'zephyr';
47271             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
47272             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
47273                 $urlRouterProvider.otherwise('/execution');
47274                 $locationProvider.html5Mode({
47275                     enabled: true,
47276                     requireBase: false
47277                 });
47278                 $stateProvider
47279                     .state('execution', {
47280                     url: '/execution',
47281                     templateUrl: 'templates/execution.html',
47282                     controller: 'executionController',
47283                     controllerAs: 'c'
47284                 })
47285                     .state('workspace', {
47286                     url: '/workspace',
47287                     templateUrl: 'templates/workspace.html',
47288                     controller: 'workspaceController',
47289                     controllerAs: 'c'
47290                 })
47291                     .state('history', {
47292                     url: '/history',
47293                     templateUrl: 'templates/history.html',
47294                     controller: 'historyController',
47295                     controllerAs: 'c'
47296                 });
47297             });
47298             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
47299             app.zephyr.service('MyModal', app.services.MyModal);
47300             app.zephyr.service('WebSocket', app.services.WebSocket);
47301             app.zephyr.service('Console', app.services.Console);
47302             app.zephyr.filter('Tag', filters.Tag);
47303             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
47304             app.zephyr.controller('previewController', app.controllers.Preview);
47305             app.zephyr.controller('executionController', app.controllers.Execution);
47306             app.zephyr.controller('workspaceController', app.controllers.Workspace);
47307             app.zephyr.controller('historyController', app.controllers.History);
47308             app.zephyr.controller('commandController', app.directives.CommandController);
47309             app.zephyr.controller('optionController', app.directives.OptionController);
47310             app.zephyr.controller('directoryController', app.directives.DirectoryController);
47311             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
47312             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
47313             app.zephyr.directive('command', app.directives.Command.Factory());
47314             app.zephyr.directive('option', app.directives.Option.Factory());
47315             app.zephyr.directive('directory', app.directives.Directory.Factory());
47316         })(app || (app = {}));
47317
47318
47319 /***/ },
47320 /* 17 */
47321 /***/ function(module, exports) {
47322
47323         var app;
47324         (function (app) {
47325             var declares;
47326             (function (declares) {
47327                 var CommandInfo = (function () {
47328                     function CommandInfo(name) {
47329                         this.name = name;
47330                     }
47331                     return CommandInfo;
47332                 })();
47333                 declares.CommandInfo = CommandInfo;
47334             })(declares = app.declares || (app.declares = {}));
47335         })(app || (app = {}));
47336         var app;
47337         (function (app) {
47338             var services;
47339             (function (services) {
47340                 var APIEndPoint = (function () {
47341                     function APIEndPoint($resource, $http) {
47342                         this.$resource = $resource;
47343                         this.$http = $http;
47344                     }
47345                     APIEndPoint.prototype.resource = function (endPoint, data) {
47346                         var customAction = {
47347                             method: 'GET',
47348                             isArray: false
47349                         };
47350                         var execute = {
47351                             method: 'POST',
47352                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
47353                         };
47354                         return this.$resource(endPoint, {}, { execute: execute });
47355                     };
47356                     APIEndPoint.prototype.getOptionControlFile = function (command) {
47357                         var endPoint = '/api/v1/optionControlFile/' + command;
47358                         return this.resource(endPoint, {}).get();
47359                     };
47360                     APIEndPoint.prototype.getFiles = function (fileId) {
47361                         var endPoint = '/api/v1/workspace';
47362                         if (fileId) {
47363                             endPoint += '/' + fileId;
47364                         }
47365                         return this.resource(endPoint, {}).get();
47366                     };
47367                     APIEndPoint.prototype.getDirectories = function () {
47368                         var endPoint = '/api/v1/all/workspace/directory';
47369                         return this.resource(endPoint, {}).get();
47370                     };
47371                     APIEndPoint.prototype.getTags = function () {
47372                         var endPoint = '/api/v1/tagList';
47373                         return this.resource(endPoint, {}).get();
47374                     };
47375                     APIEndPoint.prototype.getCommands = function () {
47376                         var endPoint = '/api/v1/commandList';
47377                         return this.resource(endPoint, {}).get();
47378                     };
47379                     APIEndPoint.prototype.execute = function (data) {
47380                         var endPoint = '/api/v1/execution';
47381                         var fd = new FormData();
47382                         fd.append('data', data);
47383                         return this.$http.post(endPoint, fd, {
47384                             headers: { 'Content-Type': undefined },
47385                             transformRequest: angular.identity
47386                         });
47387                     };
47388                     APIEndPoint.prototype.debug = function () {
47389                         var endPoint = '/api/v1/debug';
47390                         return this.$http.get(endPoint);
47391                     };
47392                     APIEndPoint.prototype.help = function (command) {
47393                         var endPoint = '/api/v1/help/' + command;
47394                         return this.$http.get(endPoint);
47395                     };
47396                     return APIEndPoint;
47397                 })();
47398                 services.APIEndPoint = APIEndPoint;
47399             })(services = app.services || (app.services = {}));
47400         })(app || (app = {}));
47401         var app;
47402         (function (app) {
47403             var services;
47404             (function (services) {
47405                 var MyModal = (function () {
47406                     function MyModal($uibModal) {
47407                         this.$uibModal = $uibModal;
47408                         this.modalOption = {
47409                             backdrop: true,
47410                             controller: null,
47411                             templateUrl: null,
47412                             size: null
47413                         };
47414                     }
47415                     MyModal.prototype.open = function (modalName) {
47416                         if (modalName === 'SelectCommand') {
47417                             this.modalOption.templateUrl = 'templates/select-command.html';
47418                             this.modalOption.size = 'lg';
47419                         }
47420                         return this.$uibModal.open(this.modalOption);
47421                     };
47422                     MyModal.prototype.selectCommand = function () {
47423                         this.modalOption.templateUrl = 'templates/select-command.html';
47424                         this.modalOption.controller = 'selectCommandController';
47425                         this.modalOption.controllerAs = 'c';
47426                         this.modalOption.size = 'lg';
47427                         return this.$uibModal.open(this.modalOption);
47428                     };
47429                     MyModal.prototype.preview = function () {
47430                         this.modalOption.templateUrl = 'templates/preview.html';
47431                         this.modalOption.controller = 'previewController';
47432                         this.modalOption.controllerAs = 'c';
47433                         this.modalOption.size = 'lg';
47434                         return this.$uibModal.open(this.modalOption);
47435                     };
47436                     MyModal.$inject = ['$uibModal'];
47437                     return MyModal;
47438                 })();
47439                 services.MyModal = MyModal;
47440             })(services = app.services || (app.services = {}));
47441         })(app || (app = {}));
47442         var app;
47443         (function (app) {
47444             var services;
47445             (function (services) {
47446                 var WebSocket = (function () {
47447                     function WebSocket($rootScope) {
47448                         this.$rootScope = $rootScope;
47449                         this.socket = io.connect();
47450                     }
47451                     WebSocket.prototype.on = function (eventName, callback) {
47452                         var socket = this.socket;
47453                         var rootScope = this.$rootScope;
47454                         socket.on(eventName, function () {
47455                             var args = arguments;
47456                             rootScope.$apply(function () {
47457                                 callback.apply(socket, args);
47458                             });
47459                         });
47460                     };
47461                     WebSocket.prototype.emit = function (eventName, data, callback) {
47462                         var socket = this.socket;
47463                         var rootScope = this.$rootScope;
47464                         this.socket.emit(eventName, data, function () {
47465                             var args = arguments;
47466                             rootScope.$apply(function () {
47467                                 if (callback)
47468                                     callback.apply(socket, args);
47469                             });
47470                         });
47471                     };
47472                     return WebSocket;
47473                 })();
47474                 services.WebSocket = WebSocket;
47475             })(services = app.services || (app.services = {}));
47476         })(app || (app = {}));
47477         var app;
47478         (function (app) {
47479             var services;
47480             (function (services) {
47481                 var Console = (function () {
47482                     function Console(WebSocket, $rootScope) {
47483                         this.WebSocket = WebSocket;
47484                         this.$rootScope = $rootScope;
47485                         this.WebSocket = WebSocket;
47486                         this.$rootScope = $rootScope;
47487                         this.directiveIDs = [];
47488                         var directiveIDs = this.directiveIDs;
47489                         this.WebSocket.on('console', function (d) {
47490                             var id = d.id;
47491                             var message = d.message;
47492                             if (directiveIDs.indexOf(id) > -1) {
47493                                 $rootScope.$emit(id, message);
47494                             }
47495                         });
47496                     }
47497                     Console.prototype.addDirective = function (id) {
47498                         if (!(this.directiveIDs.indexOf(id) > -1)) {
47499                             this.directiveIDs.push(id);
47500                         }
47501                     };
47502                     Console.prototype.removeDirective = function (id) {
47503                         var i = this.directiveIDs.indexOf(id);
47504                         if (i > -1) {
47505                             this.directiveIDs.splice(i, 1);
47506                         }
47507                     };
47508                     Console.prototype.showIDs = function () {
47509                         console.log(this.directiveIDs);
47510                     };
47511                     return Console;
47512                 })();
47513                 services.Console = Console;
47514             })(services = app.services || (app.services = {}));
47515         })(app || (app = {}));
47516         var app;
47517         (function (app) {
47518             var directives;
47519             (function (directives) {
47520                 var Command = (function () {
47521                     function Command() {
47522                         this.restrict = 'E';
47523                         this.replace = true;
47524                         this.scope = true;
47525                         this.controller = 'commandController';
47526                         this.controllerAs = 'ctrl';
47527                         this.bindToController = {
47528                             index: '=',
47529                             name: '=',
47530                             remove: '&',
47531                             list: '='
47532                         };
47533                         this.templateUrl = 'templates/command.html';
47534                     }
47535                     Command.Factory = function () {
47536                         var directive = function () {
47537                             return new Command();
47538                         };
47539                         directive.$inject = [];
47540                         return directive;
47541                     };
47542                     return Command;
47543                 })();
47544                 directives.Command = Command;
47545                 var CommandController = (function () {
47546                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
47547                         this.APIEndPoint = APIEndPoint;
47548                         this.$scope = $scope;
47549                         this.MyModal = MyModal;
47550                         this.WebSocket = WebSocket;
47551                         this.$window = $window;
47552                         this.$rootScope = $rootScope;
47553                         this.Console = Console;
47554                         var controller = this;
47555                         this.APIEndPoint
47556                             .getOptionControlFile(this.name)
47557                             .$promise
47558                             .then(function (result) {
47559                             controller.options = result.info;
47560                         });
47561                         this.APIEndPoint
47562                             .getDirectories()
47563                             .$promise
47564                             .then(function (result) {
47565                             controller.dirs = result.info;
47566                         });
47567                         this.heading = "[" + this.index + "]: dcdFilePrint";
47568                         this.isOpen = true;
47569                         this.$scope.$on('close', function () {
47570                             controller.isOpen = false;
47571                         });
47572                         function guid() {
47573                             function s4() {
47574                                 return Math.floor((1 + Math.random()) * 0x10000)
47575                                     .toString(16)
47576                                     .substring(1);
47577                             }
47578                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
47579                                 s4() + '-' + s4() + s4() + s4();
47580                         }
47581                         this.uuid = guid();
47582                         this.Console.addDirective(this.uuid);
47583                         this.Console.showIDs();
47584                     }
47585                     CommandController.prototype.submit = function () {
47586                         var opt = [];
47587                         angular.forEach(this.options, function (option) {
47588                             var obj = {
47589                                 name: option.option,
47590                                 arguments: []
47591                             };
47592                             angular.forEach(option.arg, function (arg) {
47593                                 if (arg.input) {
47594                                     if (typeof arg.input === 'object') {
47595                                         obj.arguments.push(arg.input.name);
47596                                     }
47597                                     else {
47598                                         obj.arguments.push(arg.input);
47599                                     }
47600                                 }
47601                             });
47602                             if (obj.arguments.length > 0) {
47603                                 opt.push(obj);
47604                             }
47605                         });
47606                         var execObj = {
47607                             command: this.name,
47608                             workspace: this.workspace.fileId,
47609                             options: opt
47610                         };
47611                         this.APIEndPoint
47612                             .execute(JSON.stringify(execObj))
47613                             .then(function (result) {
47614                             console.log(result);
47615                         });
47616                     };
47617                     CommandController.prototype.removeMySelf = function (index) {
47618                         this.$scope.$destroy();
47619                         this.Console.removeDirective(this.uuid);
47620                         this.remove()(index, this.list);
47621                         this.Console.showIDs();
47622                     };
47623                     CommandController.prototype.reloadFiles = function () {
47624                         var _this = this;
47625                         var fileId = this.workspace.fileId;
47626                         this.APIEndPoint
47627                             .getFiles(fileId)
47628                             .$promise
47629                             .then(function (result) {
47630                             var status = result.status;
47631                             if (status === 'success') {
47632                                 _this.files = result.info;
47633                             }
47634                             else {
47635                                 console.log(result.message);
47636                             }
47637                         });
47638                     };
47639                     CommandController.prototype.debug = function () {
47640                         var div = angular.element(this.$window.document).find("div");
47641                         var consoleTag;
47642                         var parametersTag;
47643                         angular.forEach(div, function (v) {
47644                             if (v.className === "panel-body console") {
47645                                 consoleTag = v;
47646                             }
47647                             else if (v.className === "row parameters-console") {
47648                                 parametersTag = v;
47649                             }
47650                         });
47651                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
47652                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
47653                         consoleTag.style.height = consoleHeight;
47654                         consoleTag.style.width = consoleWidth;
47655                     };
47656                     CommandController.prototype.help = function () {
47657                         this.APIEndPoint
47658                             .help(this.name)
47659                             .then(function (result) {
47660                             console.log(result);
47661                         });
47662                     };
47663                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
47664                     return CommandController;
47665                 })();
47666                 directives.CommandController = CommandController;
47667             })(directives = app.directives || (app.directives = {}));
47668         })(app || (app = {}));
47669         var app;
47670         (function (app) {
47671             var directives;
47672             (function (directives) {
47673                 var HeaderMenu = (function () {
47674                     function HeaderMenu() {
47675                         this.restrict = 'E';
47676                         this.replace = true;
47677                         this.templateUrl = 'templates/header-menu.html';
47678                         this.controller = 'HeaderMenuController';
47679                         this.controllerAs = 'hmc';
47680                         this.scope = true;
47681                     }
47682                     HeaderMenu.Factory = function () {
47683                         var directive = function () {
47684                             return new HeaderMenu();
47685                         };
47686                         return directive;
47687                     };
47688                     return HeaderMenu;
47689                 })();
47690                 directives.HeaderMenu = HeaderMenu;
47691                 var HeaderMenuController = (function () {
47692                     function HeaderMenuController($state) {
47693                         this.$state = $state;
47694                         this.isExecution = this.$state.current.name === 'execution';
47695                         this.isWorkspace = this.$state.current.name === 'workspace';
47696                         this.isHistory = this.$state.current.name === 'history';
47697                     }
47698                     HeaderMenuController.prototype.transit = function (state) {
47699                         this.$state.go(state);
47700                     };
47701                     HeaderMenuController.$inject = ['$state'];
47702                     return HeaderMenuController;
47703                 })();
47704                 directives.HeaderMenuController = HeaderMenuController;
47705             })(directives = app.directives || (app.directives = {}));
47706         })(app || (app = {}));
47707         var app;
47708         (function (app) {
47709             var directives;
47710             (function (directives) {
47711                 var Option = (function () {
47712                     function Option() {
47713                         this.restrict = 'E';
47714                         this.replace = true;
47715                         this.controller = 'optionController';
47716                         this.bindToController = {
47717                             info: '=',
47718                             files: '='
47719                         };
47720                         this.scope = true;
47721                         this.templateUrl = 'templates/option.html';
47722                         this.controllerAs = 'ctrl';
47723                     }
47724                     Option.Factory = function () {
47725                         var directive = function () {
47726                             return new Option();
47727                         };
47728                         directive.$inject = [];
47729                         return directive;
47730                     };
47731                     return Option;
47732                 })();
47733                 directives.Option = Option;
47734                 var OptionController = (function () {
47735                     function OptionController() {
47736                         var controller = this;
47737                         angular.forEach(controller.info.arg, function (arg) {
47738                             if (arg.initialValue) {
47739                                 if (arg.formType === 'number') {
47740                                     arg.input = parseInt(arg.initialValue);
47741                                 }
47742                                 else {
47743                                     arg.input = arg.initialValue;
47744                                 }
47745                             }
47746                         });
47747                     }
47748                     OptionController.$inject = [];
47749                     return OptionController;
47750                 })();
47751                 directives.OptionController = OptionController;
47752             })(directives = app.directives || (app.directives = {}));
47753         })(app || (app = {}));
47754         var app;
47755         (function (app) {
47756             var directives;
47757             (function (directives) {
47758                 var Directory = (function () {
47759                     function Directory() {
47760                         this.restrict = 'E';
47761                         this.replace = true;
47762                         this.controller = 'directoryController';
47763                         this.controllerAs = 'ctrl';
47764                         this.bindToController = {
47765                             info: '=',
47766                             add: '&',
47767                             list: '=',
47768                             files: '='
47769                         };
47770                         this.templateUrl = 'templates/directory.html';
47771                     }
47772                     Directory.Factory = function () {
47773                         var directive = function () {
47774                             return new Directory();
47775                         };
47776                         return directive;
47777                     };
47778                     return Directory;
47779                 })();
47780                 directives.Directory = Directory;
47781                 var DirectoryController = (function () {
47782                     function DirectoryController(APIEndPoint, $scope) {
47783                         this.APIEndPoint = APIEndPoint;
47784                         this.$scope = $scope;
47785                         var controller = this;
47786                         this.APIEndPoint
47787                             .getFiles(this.info.fileId)
47788                             .$promise
47789                             .then(function (result) {
47790                             if (result.status === 'success') {
47791                                 controller.files = result.info;
47792                                 angular.forEach(result.info, function (file) {
47793                                     if (file.fileType === '0') {
47794                                         var o = file;
47795                                         if (controller.info.path === '/') {
47796                                             o.path = '/' + file.name;
47797                                         }
47798                                         else {
47799                                             o.path = controller.info.path + '/' + file.name;
47800                                         }
47801                                         controller.add()(o, controller.list);
47802                                     }
47803                                 });
47804                             }
47805                             ;
47806                         });
47807                     }
47808                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
47809                     return DirectoryController;
47810                 })();
47811                 directives.DirectoryController = DirectoryController;
47812             })(directives = app.directives || (app.directives = {}));
47813         })(app || (app = {}));
47814         var app;
47815         (function (app) {
47816             var controllers;
47817             (function (controllers) {
47818                 var Execution = (function () {
47819                     function Execution(MyModal, $scope) {
47820                         this.MyModal = MyModal;
47821                         this.$scope = $scope;
47822                         this.commandInfoList = [];
47823                     }
47824                     ;
47825                     Execution.prototype.add = function () {
47826                         this.$scope.$broadcast('close');
47827                         var commandInfoList = this.commandInfoList;
47828                         var commandInstance = this.MyModal.selectCommand();
47829                         commandInstance
47830                             .result
47831                             .then(function (command) {
47832                             commandInfoList.push(new app.declares.CommandInfo(command));
47833                         });
47834                     };
47835                     Execution.prototype.open = function () {
47836                         var result = this.MyModal.open('SelectCommand');
47837                         console.log(result);
47838                     };
47839                     Execution.prototype.remove = function (index, list) {
47840                         list.splice(index, 1);
47841                     };
47842                     Execution.prototype.close = function () {
47843                         console.log("close");
47844                     };
47845                     Execution.$inject = ['MyModal', '$scope'];
47846                     return Execution;
47847                 })();
47848                 controllers.Execution = Execution;
47849             })(controllers = app.controllers || (app.controllers = {}));
47850         })(app || (app = {}));
47851         var app;
47852         (function (app) {
47853             var controllers;
47854             (function (controllers) {
47855                 var Workspace = (function () {
47856                     function Workspace($scope, APIEndPoint, MyModal) {
47857                         this.$scope = $scope;
47858                         this.APIEndPoint = APIEndPoint;
47859                         this.MyModal = MyModal;
47860                         this.directoryList = [];
47861                         var controller = this;
47862                         var directoryList = this.directoryList;
47863                         var o = {
47864                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
47865                             name: '',
47866                             parentId: '',
47867                             fileType: '',
47868                             createdAt: '',
47869                             updatedAt: '',
47870                             path: '/'
47871                         };
47872                         directoryList.push(o);
47873                     }
47874                     Workspace.prototype.addDirectory = function (info, directoryList) {
47875                         directoryList.push(info);
47876                     };
47877                     Workspace.prototype.debug = function () {
47878                         this.MyModal.preview();
47879                     };
47880                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
47881                     return Workspace;
47882                 })();
47883                 controllers.Workspace = Workspace;
47884             })(controllers = app.controllers || (app.controllers = {}));
47885         })(app || (app = {}));
47886         var app;
47887         (function (app) {
47888             var controllers;
47889             (function (controllers) {
47890                 var History = (function () {
47891                     function History($scope) {
47892                         this.page = "History";
47893                     }
47894                     History.$inject = ['$scope'];
47895                     return History;
47896                 })();
47897                 controllers.History = History;
47898             })(controllers = app.controllers || (app.controllers = {}));
47899         })(app || (app = {}));
47900         var app;
47901         (function (app) {
47902             var controllers;
47903             (function (controllers) {
47904                 var SelectCommand = (function () {
47905                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
47906                         this.APIEndPoint = APIEndPoint;
47907                         this.$modalInstance = $modalInstance;
47908                         var controller = this;
47909                         this.APIEndPoint
47910                             .getTags()
47911                             .$promise.then(function (result) {
47912                             controller.tags = result.info;
47913                         });
47914                         this.APIEndPoint
47915                             .getCommands()
47916                             .$promise.then(function (result) {
47917                             controller.commands = result.info;
47918                         });
47919                         this.currentTag = 'all';
47920                     }
47921                     SelectCommand.prototype.changeTag = function (tag) {
47922                         this.currentTag = tag;
47923                     };
47924                     SelectCommand.prototype.selectCommand = function (command) {
47925                         this.$modalInstance.close(command);
47926                     };
47927                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47928                     return SelectCommand;
47929                 })();
47930                 controllers.SelectCommand = SelectCommand;
47931             })(controllers = app.controllers || (app.controllers = {}));
47932         })(app || (app = {}));
47933         var app;
47934         (function (app) {
47935             var controllers;
47936             (function (controllers) {
47937                 var Preview = (function () {
47938                     function Preview($scope, APIEndPoint, $modalInstance) {
47939                         this.APIEndPoint = APIEndPoint;
47940                         this.$modalInstance = $modalInstance;
47941                         var controller = this;
47942                         console.log('preview');
47943                     }
47944                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47945                     return Preview;
47946                 })();
47947                 controllers.Preview = Preview;
47948             })(controllers = app.controllers || (app.controllers = {}));
47949         })(app || (app = {}));
47950         var filters;
47951         (function (filters) {
47952             function Tag() {
47953                 return function (commands, tag) {
47954                     var result = [];
47955                     angular.forEach(commands, function (command) {
47956                         var flag = false;
47957                         angular.forEach(command.tags, function (value) {
47958                             if (tag === value)
47959                                 flag = true;
47960                         });
47961                         if (flag)
47962                             result.push(command);
47963                     });
47964                     return result;
47965                 };
47966             }
47967             filters.Tag = Tag;
47968         })(filters || (filters = {}));
47969         var app;
47970         (function (app) {
47971             'use strict';
47972             var appName = 'zephyr';
47973             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
47974             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
47975                 $urlRouterProvider.otherwise('/execution');
47976                 $locationProvider.html5Mode({
47977                     enabled: true,
47978                     requireBase: false
47979                 });
47980                 $stateProvider
47981                     .state('execution', {
47982                     url: '/execution',
47983                     templateUrl: 'templates/execution.html',
47984                     controller: 'executionController',
47985                     controllerAs: 'c'
47986                 })
47987                     .state('workspace', {
47988                     url: '/workspace',
47989                     templateUrl: 'templates/workspace.html',
47990                     controller: 'workspaceController',
47991                     controllerAs: 'c'
47992                 })
47993                     .state('history', {
47994                     url: '/history',
47995                     templateUrl: 'templates/history.html',
47996                     controller: 'historyController',
47997                     controllerAs: 'c'
47998                 });
47999             });
48000             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
48001             app.zephyr.service('MyModal', app.services.MyModal);
48002             app.zephyr.service('WebSocket', app.services.WebSocket);
48003             app.zephyr.service('Console', app.services.Console);
48004             app.zephyr.filter('Tag', filters.Tag);
48005             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
48006             app.zephyr.controller('previewController', app.controllers.Preview);
48007             app.zephyr.controller('executionController', app.controllers.Execution);
48008             app.zephyr.controller('workspaceController', app.controllers.Workspace);
48009             app.zephyr.controller('historyController', app.controllers.History);
48010             app.zephyr.controller('commandController', app.directives.CommandController);
48011             app.zephyr.controller('optionController', app.directives.OptionController);
48012             app.zephyr.controller('directoryController', app.directives.DirectoryController);
48013             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
48014             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
48015             app.zephyr.directive('command', app.directives.Command.Factory());
48016             app.zephyr.directive('option', app.directives.Option.Factory());
48017             app.zephyr.directive('directory', app.directives.Directory.Factory());
48018         })(app || (app = {}));
48019
48020
48021 /***/ },
48022 /* 18 */
48023 /***/ function(module, exports) {
48024
48025         var app;
48026         (function (app) {
48027             var declares;
48028             (function (declares) {
48029                 var CommandInfo = (function () {
48030                     function CommandInfo(name) {
48031                         this.name = name;
48032                     }
48033                     return CommandInfo;
48034                 })();
48035                 declares.CommandInfo = CommandInfo;
48036             })(declares = app.declares || (app.declares = {}));
48037         })(app || (app = {}));
48038         var app;
48039         (function (app) {
48040             var services;
48041             (function (services) {
48042                 var APIEndPoint = (function () {
48043                     function APIEndPoint($resource, $http) {
48044                         this.$resource = $resource;
48045                         this.$http = $http;
48046                     }
48047                     APIEndPoint.prototype.resource = function (endPoint, data) {
48048                         var customAction = {
48049                             method: 'GET',
48050                             isArray: false
48051                         };
48052                         var execute = {
48053                             method: 'POST',
48054                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
48055                         };
48056                         return this.$resource(endPoint, {}, { execute: execute });
48057                     };
48058                     APIEndPoint.prototype.getOptionControlFile = function (command) {
48059                         var endPoint = '/api/v1/optionControlFile/' + command;
48060                         return this.resource(endPoint, {}).get();
48061                     };
48062                     APIEndPoint.prototype.getFiles = function (fileId) {
48063                         var endPoint = '/api/v1/workspace';
48064                         if (fileId) {
48065                             endPoint += '/' + fileId;
48066                         }
48067                         return this.resource(endPoint, {}).get();
48068                     };
48069                     APIEndPoint.prototype.getDirectories = function () {
48070                         var endPoint = '/api/v1/all/workspace/directory';
48071                         return this.resource(endPoint, {}).get();
48072                     };
48073                     APIEndPoint.prototype.getTags = function () {
48074                         var endPoint = '/api/v1/tagList';
48075                         return this.resource(endPoint, {}).get();
48076                     };
48077                     APIEndPoint.prototype.getCommands = function () {
48078                         var endPoint = '/api/v1/commandList';
48079                         return this.resource(endPoint, {}).get();
48080                     };
48081                     APIEndPoint.prototype.execute = function (data) {
48082                         var endPoint = '/api/v1/execution';
48083                         var fd = new FormData();
48084                         fd.append('data', data);
48085                         return this.$http.post(endPoint, fd, {
48086                             headers: { 'Content-Type': undefined },
48087                             transformRequest: angular.identity
48088                         });
48089                     };
48090                     APIEndPoint.prototype.debug = function () {
48091                         var endPoint = '/api/v1/debug';
48092                         return this.$http.get(endPoint);
48093                     };
48094                     APIEndPoint.prototype.help = function (command) {
48095                         var endPoint = '/api/v1/help/' + command;
48096                         return this.$http.get(endPoint);
48097                     };
48098                     return APIEndPoint;
48099                 })();
48100                 services.APIEndPoint = APIEndPoint;
48101             })(services = app.services || (app.services = {}));
48102         })(app || (app = {}));
48103         var app;
48104         (function (app) {
48105             var services;
48106             (function (services) {
48107                 var MyModal = (function () {
48108                     function MyModal($uibModal) {
48109                         this.$uibModal = $uibModal;
48110                         this.modalOption = {
48111                             backdrop: true,
48112                             controller: null,
48113                             templateUrl: null,
48114                             size: null
48115                         };
48116                     }
48117                     MyModal.prototype.open = function (modalName) {
48118                         if (modalName === 'SelectCommand') {
48119                             this.modalOption.templateUrl = 'templates/select-command.html';
48120                             this.modalOption.size = 'lg';
48121                         }
48122                         return this.$uibModal.open(this.modalOption);
48123                     };
48124                     MyModal.prototype.selectCommand = function () {
48125                         this.modalOption.templateUrl = 'templates/select-command.html';
48126                         this.modalOption.controller = 'selectCommandController';
48127                         this.modalOption.controllerAs = 'c';
48128                         this.modalOption.size = 'lg';
48129                         return this.$uibModal.open(this.modalOption);
48130                     };
48131                     MyModal.prototype.preview = function () {
48132                         this.modalOption.templateUrl = 'templates/preview.html';
48133                         this.modalOption.controller = 'previewController';
48134                         this.modalOption.controllerAs = 'c';
48135                         this.modalOption.size = 'lg';
48136                         return this.$uibModal.open(this.modalOption);
48137                     };
48138                     MyModal.$inject = ['$uibModal'];
48139                     return MyModal;
48140                 })();
48141                 services.MyModal = MyModal;
48142             })(services = app.services || (app.services = {}));
48143         })(app || (app = {}));
48144         var app;
48145         (function (app) {
48146             var services;
48147             (function (services) {
48148                 var WebSocket = (function () {
48149                     function WebSocket($rootScope) {
48150                         this.$rootScope = $rootScope;
48151                         this.socket = io.connect();
48152                     }
48153                     WebSocket.prototype.on = function (eventName, callback) {
48154                         var socket = this.socket;
48155                         var rootScope = this.$rootScope;
48156                         socket.on(eventName, function () {
48157                             var args = arguments;
48158                             rootScope.$apply(function () {
48159                                 callback.apply(socket, args);
48160                             });
48161                         });
48162                     };
48163                     WebSocket.prototype.emit = function (eventName, data, callback) {
48164                         var socket = this.socket;
48165                         var rootScope = this.$rootScope;
48166                         this.socket.emit(eventName, data, function () {
48167                             var args = arguments;
48168                             rootScope.$apply(function () {
48169                                 if (callback)
48170                                     callback.apply(socket, args);
48171                             });
48172                         });
48173                     };
48174                     return WebSocket;
48175                 })();
48176                 services.WebSocket = WebSocket;
48177             })(services = app.services || (app.services = {}));
48178         })(app || (app = {}));
48179         var app;
48180         (function (app) {
48181             var services;
48182             (function (services) {
48183                 var Console = (function () {
48184                     function Console(WebSocket, $rootScope) {
48185                         this.WebSocket = WebSocket;
48186                         this.$rootScope = $rootScope;
48187                         this.WebSocket = WebSocket;
48188                         this.$rootScope = $rootScope;
48189                         this.directiveIDs = [];
48190                         var directiveIDs = this.directiveIDs;
48191                         this.WebSocket.on('console', function (d) {
48192                             var id = d.id;
48193                             var message = d.message;
48194                             if (directiveIDs.indexOf(id) > -1) {
48195                                 $rootScope.$emit(id, message);
48196                             }
48197                         });
48198                     }
48199                     Console.prototype.addDirective = function (id) {
48200                         if (!(this.directiveIDs.indexOf(id) > -1)) {
48201                             this.directiveIDs.push(id);
48202                         }
48203                     };
48204                     Console.prototype.removeDirective = function (id) {
48205                         var i = this.directiveIDs.indexOf(id);
48206                         if (i > -1) {
48207                             this.directiveIDs.splice(i, 1);
48208                         }
48209                     };
48210                     Console.prototype.showIDs = function () {
48211                         console.log(this.directiveIDs);
48212                     };
48213                     return Console;
48214                 })();
48215                 services.Console = Console;
48216             })(services = app.services || (app.services = {}));
48217         })(app || (app = {}));
48218         var app;
48219         (function (app) {
48220             var directives;
48221             (function (directives) {
48222                 var Command = (function () {
48223                     function Command() {
48224                         this.restrict = 'E';
48225                         this.replace = true;
48226                         this.scope = true;
48227                         this.controller = 'commandController';
48228                         this.controllerAs = 'ctrl';
48229                         this.bindToController = {
48230                             index: '=',
48231                             name: '=',
48232                             remove: '&',
48233                             list: '='
48234                         };
48235                         this.templateUrl = 'templates/command.html';
48236                     }
48237                     Command.Factory = function () {
48238                         var directive = function () {
48239                             return new Command();
48240                         };
48241                         directive.$inject = [];
48242                         return directive;
48243                     };
48244                     return Command;
48245                 })();
48246                 directives.Command = Command;
48247                 var CommandController = (function () {
48248                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
48249                         this.APIEndPoint = APIEndPoint;
48250                         this.$scope = $scope;
48251                         this.MyModal = MyModal;
48252                         this.WebSocket = WebSocket;
48253                         this.$window = $window;
48254                         this.$rootScope = $rootScope;
48255                         this.Console = Console;
48256                         var controller = this;
48257                         this.APIEndPoint
48258                             .getOptionControlFile(this.name)
48259                             .$promise
48260                             .then(function (result) {
48261                             controller.options = result.info;
48262                         });
48263                         this.APIEndPoint
48264                             .getDirectories()
48265                             .$promise
48266                             .then(function (result) {
48267                             controller.dirs = result.info;
48268                         });
48269                         this.heading = "[" + this.index + "]: dcdFilePrint";
48270                         this.isOpen = true;
48271                         this.$scope.$on('close', function () {
48272                             controller.isOpen = false;
48273                         });
48274                         function guid() {
48275                             function s4() {
48276                                 return Math.floor((1 + Math.random()) * 0x10000)
48277                                     .toString(16)
48278                                     .substring(1);
48279                             }
48280                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
48281                                 s4() + '-' + s4() + s4() + s4();
48282                         }
48283                         this.uuid = guid();
48284                         this.Console.addDirective(this.uuid);
48285                         this.Console.showIDs();
48286                     }
48287                     CommandController.prototype.submit = function () {
48288                         var opt = [];
48289                         angular.forEach(this.options, function (option) {
48290                             var obj = {
48291                                 name: option.option,
48292                                 arguments: []
48293                             };
48294                             angular.forEach(option.arg, function (arg) {
48295                                 if (arg.input) {
48296                                     if (typeof arg.input === 'object') {
48297                                         obj.arguments.push(arg.input.name);
48298                                     }
48299                                     else {
48300                                         obj.arguments.push(arg.input);
48301                                     }
48302                                 }
48303                             });
48304                             if (obj.arguments.length > 0) {
48305                                 opt.push(obj);
48306                             }
48307                         });
48308                         var execObj = {
48309                             command: this.name,
48310                             workspace: this.workspace.fileId,
48311                             options: opt
48312                         };
48313                         this.APIEndPoint
48314                             .execute(JSON.stringify(execObj))
48315                             .then(function (result) {
48316                             console.log(result);
48317                         });
48318                     };
48319                     CommandController.prototype.removeMySelf = function (index) {
48320                         this.$scope.$destroy();
48321                         this.Console.removeDirective(this.uuid);
48322                         this.remove()(index, this.list);
48323                         this.Console.showIDs();
48324                     };
48325                     CommandController.prototype.reloadFiles = function () {
48326                         var _this = this;
48327                         var fileId = this.workspace.fileId;
48328                         this.APIEndPoint
48329                             .getFiles(fileId)
48330                             .$promise
48331                             .then(function (result) {
48332                             var status = result.status;
48333                             if (status === 'success') {
48334                                 _this.files = result.info;
48335                             }
48336                             else {
48337                                 console.log(result.message);
48338                             }
48339                         });
48340                     };
48341                     CommandController.prototype.debug = function () {
48342                         var div = angular.element(this.$window.document).find("div");
48343                         var consoleTag;
48344                         var parametersTag;
48345                         angular.forEach(div, function (v) {
48346                             if (v.className === "panel-body console") {
48347                                 consoleTag = v;
48348                             }
48349                             else if (v.className === "row parameters-console") {
48350                                 parametersTag = v;
48351                             }
48352                         });
48353                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
48354                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
48355                         consoleTag.style.height = consoleHeight;
48356                         consoleTag.style.width = consoleWidth;
48357                     };
48358                     CommandController.prototype.help = function () {
48359                         this.APIEndPoint
48360                             .help(this.name)
48361                             .then(function (result) {
48362                             console.log(result);
48363                         });
48364                     };
48365                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
48366                     return CommandController;
48367                 })();
48368                 directives.CommandController = CommandController;
48369             })(directives = app.directives || (app.directives = {}));
48370         })(app || (app = {}));
48371         var app;
48372         (function (app) {
48373             var directives;
48374             (function (directives) {
48375                 var HeaderMenu = (function () {
48376                     function HeaderMenu() {
48377                         this.restrict = 'E';
48378                         this.replace = true;
48379                         this.templateUrl = 'templates/header-menu.html';
48380                         this.controller = 'HeaderMenuController';
48381                         this.controllerAs = 'hmc';
48382                         this.scope = true;
48383                     }
48384                     HeaderMenu.Factory = function () {
48385                         var directive = function () {
48386                             return new HeaderMenu();
48387                         };
48388                         return directive;
48389                     };
48390                     return HeaderMenu;
48391                 })();
48392                 directives.HeaderMenu = HeaderMenu;
48393                 var HeaderMenuController = (function () {
48394                     function HeaderMenuController($state) {
48395                         this.$state = $state;
48396                         this.isExecution = this.$state.current.name === 'execution';
48397                         this.isWorkspace = this.$state.current.name === 'workspace';
48398                         this.isHistory = this.$state.current.name === 'history';
48399                     }
48400                     HeaderMenuController.prototype.transit = function (state) {
48401                         this.$state.go(state);
48402                     };
48403                     HeaderMenuController.$inject = ['$state'];
48404                     return HeaderMenuController;
48405                 })();
48406                 directives.HeaderMenuController = HeaderMenuController;
48407             })(directives = app.directives || (app.directives = {}));
48408         })(app || (app = {}));
48409         var app;
48410         (function (app) {
48411             var directives;
48412             (function (directives) {
48413                 var Option = (function () {
48414                     function Option() {
48415                         this.restrict = 'E';
48416                         this.replace = true;
48417                         this.controller = 'optionController';
48418                         this.bindToController = {
48419                             info: '=',
48420                             files: '='
48421                         };
48422                         this.scope = true;
48423                         this.templateUrl = 'templates/option.html';
48424                         this.controllerAs = 'ctrl';
48425                     }
48426                     Option.Factory = function () {
48427                         var directive = function () {
48428                             return new Option();
48429                         };
48430                         directive.$inject = [];
48431                         return directive;
48432                     };
48433                     return Option;
48434                 })();
48435                 directives.Option = Option;
48436                 var OptionController = (function () {
48437                     function OptionController() {
48438                         var controller = this;
48439                         angular.forEach(controller.info.arg, function (arg) {
48440                             if (arg.initialValue) {
48441                                 if (arg.formType === 'number') {
48442                                     arg.input = parseInt(arg.initialValue);
48443                                 }
48444                                 else {
48445                                     arg.input = arg.initialValue;
48446                                 }
48447                             }
48448                         });
48449                     }
48450                     OptionController.$inject = [];
48451                     return OptionController;
48452                 })();
48453                 directives.OptionController = OptionController;
48454             })(directives = app.directives || (app.directives = {}));
48455         })(app || (app = {}));
48456         var app;
48457         (function (app) {
48458             var directives;
48459             (function (directives) {
48460                 var Directory = (function () {
48461                     function Directory() {
48462                         this.restrict = 'E';
48463                         this.replace = true;
48464                         this.controller = 'directoryController';
48465                         this.controllerAs = 'ctrl';
48466                         this.bindToController = {
48467                             info: '=',
48468                             add: '&',
48469                             list: '=',
48470                             files: '='
48471                         };
48472                         this.templateUrl = 'templates/directory.html';
48473                     }
48474                     Directory.Factory = function () {
48475                         var directive = function () {
48476                             return new Directory();
48477                         };
48478                         return directive;
48479                     };
48480                     return Directory;
48481                 })();
48482                 directives.Directory = Directory;
48483                 var DirectoryController = (function () {
48484                     function DirectoryController(APIEndPoint, $scope) {
48485                         this.APIEndPoint = APIEndPoint;
48486                         this.$scope = $scope;
48487                         var controller = this;
48488                         this.APIEndPoint
48489                             .getFiles(this.info.fileId)
48490                             .$promise
48491                             .then(function (result) {
48492                             if (result.status === 'success') {
48493                                 controller.files = result.info;
48494                                 angular.forEach(result.info, function (file) {
48495                                     if (file.fileType === '0') {
48496                                         var o = file;
48497                                         if (controller.info.path === '/') {
48498                                             o.path = '/' + file.name;
48499                                         }
48500                                         else {
48501                                             o.path = controller.info.path + '/' + file.name;
48502                                         }
48503                                         controller.add()(o, controller.list);
48504                                     }
48505                                 });
48506                             }
48507                             ;
48508                         });
48509                     }
48510                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
48511                     return DirectoryController;
48512                 })();
48513                 directives.DirectoryController = DirectoryController;
48514             })(directives = app.directives || (app.directives = {}));
48515         })(app || (app = {}));
48516         var app;
48517         (function (app) {
48518             var controllers;
48519             (function (controllers) {
48520                 var Execution = (function () {
48521                     function Execution(MyModal, $scope) {
48522                         this.MyModal = MyModal;
48523                         this.$scope = $scope;
48524                         this.commandInfoList = [];
48525                     }
48526                     ;
48527                     Execution.prototype.add = function () {
48528                         this.$scope.$broadcast('close');
48529                         var commandInfoList = this.commandInfoList;
48530                         var commandInstance = this.MyModal.selectCommand();
48531                         commandInstance
48532                             .result
48533                             .then(function (command) {
48534                             commandInfoList.push(new app.declares.CommandInfo(command));
48535                         });
48536                     };
48537                     Execution.prototype.open = function () {
48538                         var result = this.MyModal.open('SelectCommand');
48539                         console.log(result);
48540                     };
48541                     Execution.prototype.remove = function (index, list) {
48542                         list.splice(index, 1);
48543                     };
48544                     Execution.prototype.close = function () {
48545                         console.log("close");
48546                     };
48547                     Execution.$inject = ['MyModal', '$scope'];
48548                     return Execution;
48549                 })();
48550                 controllers.Execution = Execution;
48551             })(controllers = app.controllers || (app.controllers = {}));
48552         })(app || (app = {}));
48553         var app;
48554         (function (app) {
48555             var controllers;
48556             (function (controllers) {
48557                 var Workspace = (function () {
48558                     function Workspace($scope, APIEndPoint, MyModal) {
48559                         this.$scope = $scope;
48560                         this.APIEndPoint = APIEndPoint;
48561                         this.MyModal = MyModal;
48562                         this.directoryList = [];
48563                         var controller = this;
48564                         var directoryList = this.directoryList;
48565                         var o = {
48566                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
48567                             name: '',
48568                             parentId: '',
48569                             fileType: '',
48570                             createdAt: '',
48571                             updatedAt: '',
48572                             path: '/'
48573                         };
48574                         directoryList.push(o);
48575                     }
48576                     Workspace.prototype.addDirectory = function (info, directoryList) {
48577                         directoryList.push(info);
48578                     };
48579                     Workspace.prototype.debug = function () {
48580                         this.MyModal.preview();
48581                     };
48582                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
48583                     return Workspace;
48584                 })();
48585                 controllers.Workspace = Workspace;
48586             })(controllers = app.controllers || (app.controllers = {}));
48587         })(app || (app = {}));
48588         var app;
48589         (function (app) {
48590             var controllers;
48591             (function (controllers) {
48592                 var History = (function () {
48593                     function History($scope) {
48594                         this.page = "History";
48595                     }
48596                     History.$inject = ['$scope'];
48597                     return History;
48598                 })();
48599                 controllers.History = History;
48600             })(controllers = app.controllers || (app.controllers = {}));
48601         })(app || (app = {}));
48602         var app;
48603         (function (app) {
48604             var controllers;
48605             (function (controllers) {
48606                 var SelectCommand = (function () {
48607                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
48608                         this.APIEndPoint = APIEndPoint;
48609                         this.$modalInstance = $modalInstance;
48610                         var controller = this;
48611                         this.APIEndPoint
48612                             .getTags()
48613                             .$promise.then(function (result) {
48614                             controller.tags = result.info;
48615                         });
48616                         this.APIEndPoint
48617                             .getCommands()
48618                             .$promise.then(function (result) {
48619                             controller.commands = result.info;
48620                         });
48621                         this.currentTag = 'all';
48622                     }
48623                     SelectCommand.prototype.changeTag = function (tag) {
48624                         this.currentTag = tag;
48625                     };
48626                     SelectCommand.prototype.selectCommand = function (command) {
48627                         this.$modalInstance.close(command);
48628                     };
48629                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48630                     return SelectCommand;
48631                 })();
48632                 controllers.SelectCommand = SelectCommand;
48633             })(controllers = app.controllers || (app.controllers = {}));
48634         })(app || (app = {}));
48635         var app;
48636         (function (app) {
48637             var controllers;
48638             (function (controllers) {
48639                 var Preview = (function () {
48640                     function Preview($scope, APIEndPoint, $modalInstance) {
48641                         this.APIEndPoint = APIEndPoint;
48642                         this.$modalInstance = $modalInstance;
48643                         var controller = this;
48644                         console.log('preview');
48645                     }
48646                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48647                     return Preview;
48648                 })();
48649                 controllers.Preview = Preview;
48650             })(controllers = app.controllers || (app.controllers = {}));
48651         })(app || (app = {}));
48652         var filters;
48653         (function (filters) {
48654             function Tag() {
48655                 return function (commands, tag) {
48656                     var result = [];
48657                     angular.forEach(commands, function (command) {
48658                         var flag = false;
48659                         angular.forEach(command.tags, function (value) {
48660                             if (tag === value)
48661                                 flag = true;
48662                         });
48663                         if (flag)
48664                             result.push(command);
48665                     });
48666                     return result;
48667                 };
48668             }
48669             filters.Tag = Tag;
48670         })(filters || (filters = {}));
48671         var app;
48672         (function (app) {
48673             'use strict';
48674             var appName = 'zephyr';
48675             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
48676             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
48677                 $urlRouterProvider.otherwise('/execution');
48678                 $locationProvider.html5Mode({
48679                     enabled: true,
48680                     requireBase: false
48681                 });
48682                 $stateProvider
48683                     .state('execution', {
48684                     url: '/execution',
48685                     templateUrl: 'templates/execution.html',
48686                     controller: 'executionController',
48687                     controllerAs: 'c'
48688                 })
48689                     .state('workspace', {
48690                     url: '/workspace',
48691                     templateUrl: 'templates/workspace.html',
48692                     controller: 'workspaceController',
48693                     controllerAs: 'c'
48694                 })
48695                     .state('history', {
48696                     url: '/history',
48697                     templateUrl: 'templates/history.html',
48698                     controller: 'historyController',
48699                     controllerAs: 'c'
48700                 });
48701             });
48702             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
48703             app.zephyr.service('MyModal', app.services.MyModal);
48704             app.zephyr.service('WebSocket', app.services.WebSocket);
48705             app.zephyr.service('Console', app.services.Console);
48706             app.zephyr.filter('Tag', filters.Tag);
48707             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
48708             app.zephyr.controller('previewController', app.controllers.Preview);
48709             app.zephyr.controller('executionController', app.controllers.Execution);
48710             app.zephyr.controller('workspaceController', app.controllers.Workspace);
48711             app.zephyr.controller('historyController', app.controllers.History);
48712             app.zephyr.controller('commandController', app.directives.CommandController);
48713             app.zephyr.controller('optionController', app.directives.OptionController);
48714             app.zephyr.controller('directoryController', app.directives.DirectoryController);
48715             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
48716             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
48717             app.zephyr.directive('command', app.directives.Command.Factory());
48718             app.zephyr.directive('option', app.directives.Option.Factory());
48719             app.zephyr.directive('directory', app.directives.Directory.Factory());
48720         })(app || (app = {}));
48721
48722
48723 /***/ },
48724 /* 19 */
48725 /***/ function(module, exports) {
48726
48727         var app;
48728         (function (app) {
48729             var declares;
48730             (function (declares) {
48731                 var CommandInfo = (function () {
48732                     function CommandInfo(name) {
48733                         this.name = name;
48734                     }
48735                     return CommandInfo;
48736                 })();
48737                 declares.CommandInfo = CommandInfo;
48738             })(declares = app.declares || (app.declares = {}));
48739         })(app || (app = {}));
48740         var app;
48741         (function (app) {
48742             var services;
48743             (function (services) {
48744                 var APIEndPoint = (function () {
48745                     function APIEndPoint($resource, $http) {
48746                         this.$resource = $resource;
48747                         this.$http = $http;
48748                     }
48749                     APIEndPoint.prototype.resource = function (endPoint, data) {
48750                         var customAction = {
48751                             method: 'GET',
48752                             isArray: false
48753                         };
48754                         var execute = {
48755                             method: 'POST',
48756                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
48757                         };
48758                         return this.$resource(endPoint, {}, { execute: execute });
48759                     };
48760                     APIEndPoint.prototype.getOptionControlFile = function (command) {
48761                         var endPoint = '/api/v1/optionControlFile/' + command;
48762                         return this.resource(endPoint, {}).get();
48763                     };
48764                     APIEndPoint.prototype.getFiles = function (fileId) {
48765                         var endPoint = '/api/v1/workspace';
48766                         if (fileId) {
48767                             endPoint += '/' + fileId;
48768                         }
48769                         return this.resource(endPoint, {}).get();
48770                     };
48771                     APIEndPoint.prototype.getDirectories = function () {
48772                         var endPoint = '/api/v1/all/workspace/directory';
48773                         return this.resource(endPoint, {}).get();
48774                     };
48775                     APIEndPoint.prototype.getTags = function () {
48776                         var endPoint = '/api/v1/tagList';
48777                         return this.resource(endPoint, {}).get();
48778                     };
48779                     APIEndPoint.prototype.getCommands = function () {
48780                         var endPoint = '/api/v1/commandList';
48781                         return this.resource(endPoint, {}).get();
48782                     };
48783                     APIEndPoint.prototype.execute = function (data) {
48784                         var endPoint = '/api/v1/execution';
48785                         var fd = new FormData();
48786                         fd.append('data', data);
48787                         return this.$http.post(endPoint, fd, {
48788                             headers: { 'Content-Type': undefined },
48789                             transformRequest: angular.identity
48790                         });
48791                     };
48792                     APIEndPoint.prototype.debug = function () {
48793                         var endPoint = '/api/v1/debug';
48794                         return this.$http.get(endPoint);
48795                     };
48796                     APIEndPoint.prototype.help = function (command) {
48797                         var endPoint = '/api/v1/help/' + command;
48798                         return this.$http.get(endPoint);
48799                     };
48800                     return APIEndPoint;
48801                 })();
48802                 services.APIEndPoint = APIEndPoint;
48803             })(services = app.services || (app.services = {}));
48804         })(app || (app = {}));
48805         var app;
48806         (function (app) {
48807             var services;
48808             (function (services) {
48809                 var MyModal = (function () {
48810                     function MyModal($uibModal) {
48811                         this.$uibModal = $uibModal;
48812                         this.modalOption = {
48813                             backdrop: true,
48814                             controller: null,
48815                             templateUrl: null,
48816                             size: null
48817                         };
48818                     }
48819                     MyModal.prototype.open = function (modalName) {
48820                         if (modalName === 'SelectCommand') {
48821                             this.modalOption.templateUrl = 'templates/select-command.html';
48822                             this.modalOption.size = 'lg';
48823                         }
48824                         return this.$uibModal.open(this.modalOption);
48825                     };
48826                     MyModal.prototype.selectCommand = function () {
48827                         this.modalOption.templateUrl = 'templates/select-command.html';
48828                         this.modalOption.controller = 'selectCommandController';
48829                         this.modalOption.controllerAs = 'c';
48830                         this.modalOption.size = 'lg';
48831                         return this.$uibModal.open(this.modalOption);
48832                     };
48833                     MyModal.prototype.preview = function () {
48834                         this.modalOption.templateUrl = 'templates/preview.html';
48835                         this.modalOption.controller = 'previewController';
48836                         this.modalOption.controllerAs = 'c';
48837                         this.modalOption.size = 'lg';
48838                         return this.$uibModal.open(this.modalOption);
48839                     };
48840                     MyModal.$inject = ['$uibModal'];
48841                     return MyModal;
48842                 })();
48843                 services.MyModal = MyModal;
48844             })(services = app.services || (app.services = {}));
48845         })(app || (app = {}));
48846         var app;
48847         (function (app) {
48848             var services;
48849             (function (services) {
48850                 var WebSocket = (function () {
48851                     function WebSocket($rootScope) {
48852                         this.$rootScope = $rootScope;
48853                         this.socket = io.connect();
48854                     }
48855                     WebSocket.prototype.on = function (eventName, callback) {
48856                         var socket = this.socket;
48857                         var rootScope = this.$rootScope;
48858                         socket.on(eventName, function () {
48859                             var args = arguments;
48860                             rootScope.$apply(function () {
48861                                 callback.apply(socket, args);
48862                             });
48863                         });
48864                     };
48865                     WebSocket.prototype.emit = function (eventName, data, callback) {
48866                         var socket = this.socket;
48867                         var rootScope = this.$rootScope;
48868                         this.socket.emit(eventName, data, function () {
48869                             var args = arguments;
48870                             rootScope.$apply(function () {
48871                                 if (callback)
48872                                     callback.apply(socket, args);
48873                             });
48874                         });
48875                     };
48876                     return WebSocket;
48877                 })();
48878                 services.WebSocket = WebSocket;
48879             })(services = app.services || (app.services = {}));
48880         })(app || (app = {}));
48881         var app;
48882         (function (app) {
48883             var services;
48884             (function (services) {
48885                 var Console = (function () {
48886                     function Console(WebSocket, $rootScope) {
48887                         this.WebSocket = WebSocket;
48888                         this.$rootScope = $rootScope;
48889                         this.WebSocket = WebSocket;
48890                         this.$rootScope = $rootScope;
48891                         this.directiveIDs = [];
48892                         var directiveIDs = this.directiveIDs;
48893                         this.WebSocket.on('console', function (d) {
48894                             var id = d.id;
48895                             var message = d.message;
48896                             if (directiveIDs.indexOf(id) > -1) {
48897                                 $rootScope.$emit(id, message);
48898                             }
48899                         });
48900                     }
48901                     Console.prototype.addDirective = function (id) {
48902                         if (!(this.directiveIDs.indexOf(id) > -1)) {
48903                             this.directiveIDs.push(id);
48904                         }
48905                     };
48906                     Console.prototype.removeDirective = function (id) {
48907                         var i = this.directiveIDs.indexOf(id);
48908                         if (i > -1) {
48909                             this.directiveIDs.splice(i, 1);
48910                         }
48911                     };
48912                     Console.prototype.showIDs = function () {
48913                         console.log(this.directiveIDs);
48914                     };
48915                     return Console;
48916                 })();
48917                 services.Console = Console;
48918             })(services = app.services || (app.services = {}));
48919         })(app || (app = {}));
48920         var app;
48921         (function (app) {
48922             var directives;
48923             (function (directives) {
48924                 var Command = (function () {
48925                     function Command() {
48926                         this.restrict = 'E';
48927                         this.replace = true;
48928                         this.scope = true;
48929                         this.controller = 'commandController';
48930                         this.controllerAs = 'ctrl';
48931                         this.bindToController = {
48932                             index: '=',
48933                             name: '=',
48934                             remove: '&',
48935                             list: '='
48936                         };
48937                         this.templateUrl = 'templates/command.html';
48938                     }
48939                     Command.Factory = function () {
48940                         var directive = function () {
48941                             return new Command();
48942                         };
48943                         directive.$inject = [];
48944                         return directive;
48945                     };
48946                     return Command;
48947                 })();
48948                 directives.Command = Command;
48949                 var CommandController = (function () {
48950                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
48951                         this.APIEndPoint = APIEndPoint;
48952                         this.$scope = $scope;
48953                         this.MyModal = MyModal;
48954                         this.WebSocket = WebSocket;
48955                         this.$window = $window;
48956                         this.$rootScope = $rootScope;
48957                         this.Console = Console;
48958                         var controller = this;
48959                         this.APIEndPoint
48960                             .getOptionControlFile(this.name)
48961                             .$promise
48962                             .then(function (result) {
48963                             controller.options = result.info;
48964                         });
48965                         this.APIEndPoint
48966                             .getDirectories()
48967                             .$promise
48968                             .then(function (result) {
48969                             controller.dirs = result.info;
48970                         });
48971                         this.heading = "[" + this.index + "]: dcdFilePrint";
48972                         this.isOpen = true;
48973                         this.$scope.$on('close', function () {
48974                             controller.isOpen = false;
48975                         });
48976                         function guid() {
48977                             function s4() {
48978                                 return Math.floor((1 + Math.random()) * 0x10000)
48979                                     .toString(16)
48980                                     .substring(1);
48981                             }
48982                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
48983                                 s4() + '-' + s4() + s4() + s4();
48984                         }
48985                         this.uuid = guid();
48986                         this.Console.addDirective(this.uuid);
48987                         this.Console.showIDs();
48988                     }
48989                     CommandController.prototype.submit = function () {
48990                         var opt = [];
48991                         angular.forEach(this.options, function (option) {
48992                             var obj = {
48993                                 name: option.option,
48994                                 arguments: []
48995                             };
48996                             angular.forEach(option.arg, function (arg) {
48997                                 if (arg.input) {
48998                                     if (typeof arg.input === 'object') {
48999                                         obj.arguments.push(arg.input.name);
49000                                     }
49001                                     else {
49002                                         obj.arguments.push(arg.input);
49003                                     }
49004                                 }
49005                             });
49006                             if (obj.arguments.length > 0) {
49007                                 opt.push(obj);
49008                             }
49009                         });
49010                         var execObj = {
49011                             command: this.name,
49012                             workspace: this.workspace.fileId,
49013                             options: opt
49014                         };
49015                         this.APIEndPoint
49016                             .execute(JSON.stringify(execObj))
49017                             .then(function (result) {
49018                             console.log(result);
49019                         });
49020                     };
49021                     CommandController.prototype.removeMySelf = function (index) {
49022                         this.$scope.$destroy();
49023                         this.Console.removeDirective(this.uuid);
49024                         this.remove()(index, this.list);
49025                         this.Console.showIDs();
49026                     };
49027                     CommandController.prototype.reloadFiles = function () {
49028                         var _this = this;
49029                         var fileId = this.workspace.fileId;
49030                         this.APIEndPoint
49031                             .getFiles(fileId)
49032                             .$promise
49033                             .then(function (result) {
49034                             var status = result.status;
49035                             if (status === 'success') {
49036                                 _this.files = result.info;
49037                             }
49038                             else {
49039                                 console.log(result.message);
49040                             }
49041                         });
49042                     };
49043                     CommandController.prototype.debug = function () {
49044                         var div = angular.element(this.$window.document).find("div");
49045                         var consoleTag;
49046                         var parametersTag;
49047                         angular.forEach(div, function (v) {
49048                             if (v.className === "panel-body console") {
49049                                 consoleTag = v;
49050                             }
49051                             else if (v.className === "row parameters-console") {
49052                                 parametersTag = v;
49053                             }
49054                         });
49055                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
49056                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
49057                         consoleTag.style.height = consoleHeight;
49058                         consoleTag.style.width = consoleWidth;
49059                     };
49060                     CommandController.prototype.help = function () {
49061                         this.APIEndPoint
49062                             .help(this.name)
49063                             .then(function (result) {
49064                             console.log(result);
49065                         });
49066                     };
49067                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
49068                     return CommandController;
49069                 })();
49070                 directives.CommandController = CommandController;
49071             })(directives = app.directives || (app.directives = {}));
49072         })(app || (app = {}));
49073         var app;
49074         (function (app) {
49075             var directives;
49076             (function (directives) {
49077                 var HeaderMenu = (function () {
49078                     function HeaderMenu() {
49079                         this.restrict = 'E';
49080                         this.replace = true;
49081                         this.templateUrl = 'templates/header-menu.html';
49082                         this.controller = 'HeaderMenuController';
49083                         this.controllerAs = 'hmc';
49084                         this.scope = true;
49085                     }
49086                     HeaderMenu.Factory = function () {
49087                         var directive = function () {
49088                             return new HeaderMenu();
49089                         };
49090                         return directive;
49091                     };
49092                     return HeaderMenu;
49093                 })();
49094                 directives.HeaderMenu = HeaderMenu;
49095                 var HeaderMenuController = (function () {
49096                     function HeaderMenuController($state) {
49097                         this.$state = $state;
49098                         this.isExecution = this.$state.current.name === 'execution';
49099                         this.isWorkspace = this.$state.current.name === 'workspace';
49100                         this.isHistory = this.$state.current.name === 'history';
49101                     }
49102                     HeaderMenuController.prototype.transit = function (state) {
49103                         this.$state.go(state);
49104                     };
49105                     HeaderMenuController.$inject = ['$state'];
49106                     return HeaderMenuController;
49107                 })();
49108                 directives.HeaderMenuController = HeaderMenuController;
49109             })(directives = app.directives || (app.directives = {}));
49110         })(app || (app = {}));
49111         var app;
49112         (function (app) {
49113             var directives;
49114             (function (directives) {
49115                 var Option = (function () {
49116                     function Option() {
49117                         this.restrict = 'E';
49118                         this.replace = true;
49119                         this.controller = 'optionController';
49120                         this.bindToController = {
49121                             info: '=',
49122                             files: '='
49123                         };
49124                         this.scope = true;
49125                         this.templateUrl = 'templates/option.html';
49126                         this.controllerAs = 'ctrl';
49127                     }
49128                     Option.Factory = function () {
49129                         var directive = function () {
49130                             return new Option();
49131                         };
49132                         directive.$inject = [];
49133                         return directive;
49134                     };
49135                     return Option;
49136                 })();
49137                 directives.Option = Option;
49138                 var OptionController = (function () {
49139                     function OptionController() {
49140                         var controller = this;
49141                         angular.forEach(controller.info.arg, function (arg) {
49142                             if (arg.initialValue) {
49143                                 if (arg.formType === 'number') {
49144                                     arg.input = parseInt(arg.initialValue);
49145                                 }
49146                                 else {
49147                                     arg.input = arg.initialValue;
49148                                 }
49149                             }
49150                         });
49151                     }
49152                     OptionController.$inject = [];
49153                     return OptionController;
49154                 })();
49155                 directives.OptionController = OptionController;
49156             })(directives = app.directives || (app.directives = {}));
49157         })(app || (app = {}));
49158         var app;
49159         (function (app) {
49160             var directives;
49161             (function (directives) {
49162                 var Directory = (function () {
49163                     function Directory() {
49164                         this.restrict = 'E';
49165                         this.replace = true;
49166                         this.controller = 'directoryController';
49167                         this.controllerAs = 'ctrl';
49168                         this.bindToController = {
49169                             info: '=',
49170                             add: '&',
49171                             list: '=',
49172                             files: '='
49173                         };
49174                         this.templateUrl = 'templates/directory.html';
49175                     }
49176                     Directory.Factory = function () {
49177                         var directive = function () {
49178                             return new Directory();
49179                         };
49180                         return directive;
49181                     };
49182                     return Directory;
49183                 })();
49184                 directives.Directory = Directory;
49185                 var DirectoryController = (function () {
49186                     function DirectoryController(APIEndPoint, $scope) {
49187                         this.APIEndPoint = APIEndPoint;
49188                         this.$scope = $scope;
49189                         var controller = this;
49190                         this.APIEndPoint
49191                             .getFiles(this.info.fileId)
49192                             .$promise
49193                             .then(function (result) {
49194                             if (result.status === 'success') {
49195                                 controller.files = result.info;
49196                                 angular.forEach(result.info, function (file) {
49197                                     if (file.fileType === '0') {
49198                                         var o = file;
49199                                         if (controller.info.path === '/') {
49200                                             o.path = '/' + file.name;
49201                                         }
49202                                         else {
49203                                             o.path = controller.info.path + '/' + file.name;
49204                                         }
49205                                         controller.add()(o, controller.list);
49206                                     }
49207                                 });
49208                             }
49209                             ;
49210                         });
49211                     }
49212                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
49213                     return DirectoryController;
49214                 })();
49215                 directives.DirectoryController = DirectoryController;
49216             })(directives = app.directives || (app.directives = {}));
49217         })(app || (app = {}));
49218         var app;
49219         (function (app) {
49220             var controllers;
49221             (function (controllers) {
49222                 var Execution = (function () {
49223                     function Execution(MyModal, $scope) {
49224                         this.MyModal = MyModal;
49225                         this.$scope = $scope;
49226                         this.commandInfoList = [];
49227                     }
49228                     ;
49229                     Execution.prototype.add = function () {
49230                         this.$scope.$broadcast('close');
49231                         var commandInfoList = this.commandInfoList;
49232                         var commandInstance = this.MyModal.selectCommand();
49233                         commandInstance
49234                             .result
49235                             .then(function (command) {
49236                             commandInfoList.push(new app.declares.CommandInfo(command));
49237                         });
49238                     };
49239                     Execution.prototype.open = function () {
49240                         var result = this.MyModal.open('SelectCommand');
49241                         console.log(result);
49242                     };
49243                     Execution.prototype.remove = function (index, list) {
49244                         list.splice(index, 1);
49245                     };
49246                     Execution.prototype.close = function () {
49247                         console.log("close");
49248                     };
49249                     Execution.$inject = ['MyModal', '$scope'];
49250                     return Execution;
49251                 })();
49252                 controllers.Execution = Execution;
49253             })(controllers = app.controllers || (app.controllers = {}));
49254         })(app || (app = {}));
49255         var app;
49256         (function (app) {
49257             var controllers;
49258             (function (controllers) {
49259                 var Workspace = (function () {
49260                     function Workspace($scope, APIEndPoint, MyModal) {
49261                         this.$scope = $scope;
49262                         this.APIEndPoint = APIEndPoint;
49263                         this.MyModal = MyModal;
49264                         this.directoryList = [];
49265                         var controller = this;
49266                         var directoryList = this.directoryList;
49267                         var o = {
49268                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
49269                             name: '',
49270                             parentId: '',
49271                             fileType: '',
49272                             createdAt: '',
49273                             updatedAt: '',
49274                             path: '/'
49275                         };
49276                         directoryList.push(o);
49277                     }
49278                     Workspace.prototype.addDirectory = function (info, directoryList) {
49279                         directoryList.push(info);
49280                     };
49281                     Workspace.prototype.debug = function () {
49282                         this.MyModal.preview();
49283                     };
49284                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
49285                     return Workspace;
49286                 })();
49287                 controllers.Workspace = Workspace;
49288             })(controllers = app.controllers || (app.controllers = {}));
49289         })(app || (app = {}));
49290         var app;
49291         (function (app) {
49292             var controllers;
49293             (function (controllers) {
49294                 var History = (function () {
49295                     function History($scope) {
49296                         this.page = "History";
49297                     }
49298                     History.$inject = ['$scope'];
49299                     return History;
49300                 })();
49301                 controllers.History = History;
49302             })(controllers = app.controllers || (app.controllers = {}));
49303         })(app || (app = {}));
49304         var app;
49305         (function (app) {
49306             var controllers;
49307             (function (controllers) {
49308                 var SelectCommand = (function () {
49309                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
49310                         this.APIEndPoint = APIEndPoint;
49311                         this.$modalInstance = $modalInstance;
49312                         var controller = this;
49313                         this.APIEndPoint
49314                             .getTags()
49315                             .$promise.then(function (result) {
49316                             controller.tags = result.info;
49317                         });
49318                         this.APIEndPoint
49319                             .getCommands()
49320                             .$promise.then(function (result) {
49321                             controller.commands = result.info;
49322                         });
49323                         this.currentTag = 'all';
49324                     }
49325                     SelectCommand.prototype.changeTag = function (tag) {
49326                         this.currentTag = tag;
49327                     };
49328                     SelectCommand.prototype.selectCommand = function (command) {
49329                         this.$modalInstance.close(command);
49330                     };
49331                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
49332                     return SelectCommand;
49333                 })();
49334                 controllers.SelectCommand = SelectCommand;
49335             })(controllers = app.controllers || (app.controllers = {}));
49336         })(app || (app = {}));
49337         var app;
49338         (function (app) {
49339             var controllers;
49340             (function (controllers) {
49341                 var Preview = (function () {
49342                     function Preview($scope, APIEndPoint, $modalInstance) {
49343                         this.APIEndPoint = APIEndPoint;
49344                         this.$modalInstance = $modalInstance;
49345                         var controller = this;
49346                         console.log('preview');
49347                     }
49348                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
49349                     return Preview;
49350                 })();
49351                 controllers.Preview = Preview;
49352             })(controllers = app.controllers || (app.controllers = {}));
49353         })(app || (app = {}));
49354         var filters;
49355         (function (filters) {
49356             function Tag() {
49357                 return function (commands, tag) {
49358                     var result = [];
49359                     angular.forEach(commands, function (command) {
49360                         var flag = false;
49361                         angular.forEach(command.tags, function (value) {
49362                             if (tag === value)
49363                                 flag = true;
49364                         });
49365                         if (flag)
49366                             result.push(command);
49367                     });
49368                     return result;
49369                 };
49370             }
49371             filters.Tag = Tag;
49372         })(filters || (filters = {}));
49373         var app;
49374         (function (app) {
49375             'use strict';
49376             var appName = 'zephyr';
49377             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
49378             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
49379                 $urlRouterProvider.otherwise('/execution');
49380                 $locationProvider.html5Mode({
49381                     enabled: true,
49382                     requireBase: false
49383                 });
49384                 $stateProvider
49385                     .state('execution', {
49386                     url: '/execution',
49387                     templateUrl: 'templates/execution.html',
49388                     controller: 'executionController',
49389                     controllerAs: 'c'
49390                 })
49391                     .state('workspace', {
49392                     url: '/workspace',
49393                     templateUrl: 'templates/workspace.html',
49394                     controller: 'workspaceController',
49395                     controllerAs: 'c'
49396                 })
49397                     .state('history', {
49398                     url: '/history',
49399                     templateUrl: 'templates/history.html',
49400                     controller: 'historyController',
49401                     controllerAs: 'c'
49402                 });
49403             });
49404             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
49405             app.zephyr.service('MyModal', app.services.MyModal);
49406             app.zephyr.service('WebSocket', app.services.WebSocket);
49407             app.zephyr.service('Console', app.services.Console);
49408             app.zephyr.filter('Tag', filters.Tag);
49409             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
49410             app.zephyr.controller('previewController', app.controllers.Preview);
49411             app.zephyr.controller('executionController', app.controllers.Execution);
49412             app.zephyr.controller('workspaceController', app.controllers.Workspace);
49413             app.zephyr.controller('historyController', app.controllers.History);
49414             app.zephyr.controller('commandController', app.directives.CommandController);
49415             app.zephyr.controller('optionController', app.directives.OptionController);
49416             app.zephyr.controller('directoryController', app.directives.DirectoryController);
49417             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
49418             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
49419             app.zephyr.directive('command', app.directives.Command.Factory());
49420             app.zephyr.directive('option', app.directives.Option.Factory());
49421             app.zephyr.directive('directory', app.directives.Directory.Factory());
49422         })(app || (app = {}));
49423
49424
49425 /***/ },
49426 /* 20 */
49427 /***/ function(module, exports) {
49428
49429         var app;
49430         (function (app) {
49431             var declares;
49432             (function (declares) {
49433                 var CommandInfo = (function () {
49434                     function CommandInfo(name) {
49435                         this.name = name;
49436                     }
49437                     return CommandInfo;
49438                 })();
49439                 declares.CommandInfo = CommandInfo;
49440             })(declares = app.declares || (app.declares = {}));
49441         })(app || (app = {}));
49442         var app;
49443         (function (app) {
49444             var services;
49445             (function (services) {
49446                 var APIEndPoint = (function () {
49447                     function APIEndPoint($resource, $http) {
49448                         this.$resource = $resource;
49449                         this.$http = $http;
49450                     }
49451                     APIEndPoint.prototype.resource = function (endPoint, data) {
49452                         var customAction = {
49453                             method: 'GET',
49454                             isArray: false
49455                         };
49456                         var execute = {
49457                             method: 'POST',
49458                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
49459                         };
49460                         return this.$resource(endPoint, {}, { execute: execute });
49461                     };
49462                     APIEndPoint.prototype.getOptionControlFile = function (command) {
49463                         var endPoint = '/api/v1/optionControlFile/' + command;
49464                         return this.resource(endPoint, {}).get();
49465                     };
49466                     APIEndPoint.prototype.getFiles = function (fileId) {
49467                         var endPoint = '/api/v1/workspace';
49468                         if (fileId) {
49469                             endPoint += '/' + fileId;
49470                         }
49471                         return this.resource(endPoint, {}).get();
49472                     };
49473                     APIEndPoint.prototype.getDirectories = function () {
49474                         var endPoint = '/api/v1/all/workspace/directory';
49475                         return this.resource(endPoint, {}).get();
49476                     };
49477                     APIEndPoint.prototype.getTags = function () {
49478                         var endPoint = '/api/v1/tagList';
49479                         return this.resource(endPoint, {}).get();
49480                     };
49481                     APIEndPoint.prototype.getCommands = function () {
49482                         var endPoint = '/api/v1/commandList';
49483                         return this.resource(endPoint, {}).get();
49484                     };
49485                     APIEndPoint.prototype.execute = function (data) {
49486                         var endPoint = '/api/v1/execution';
49487                         var fd = new FormData();
49488                         fd.append('data', data);
49489                         return this.$http.post(endPoint, fd, {
49490                             headers: { 'Content-Type': undefined },
49491                             transformRequest: angular.identity
49492                         });
49493                     };
49494                     APIEndPoint.prototype.debug = function () {
49495                         var endPoint = '/api/v1/debug';
49496                         return this.$http.get(endPoint);
49497                     };
49498                     APIEndPoint.prototype.help = function (command) {
49499                         var endPoint = '/api/v1/help/' + command;
49500                         return this.$http.get(endPoint);
49501                     };
49502                     return APIEndPoint;
49503                 })();
49504                 services.APIEndPoint = APIEndPoint;
49505             })(services = app.services || (app.services = {}));
49506         })(app || (app = {}));
49507         var app;
49508         (function (app) {
49509             var services;
49510             (function (services) {
49511                 var MyModal = (function () {
49512                     function MyModal($uibModal) {
49513                         this.$uibModal = $uibModal;
49514                         this.modalOption = {
49515                             backdrop: true,
49516                             controller: null,
49517                             templateUrl: null,
49518                             size: null
49519                         };
49520                     }
49521                     MyModal.prototype.open = function (modalName) {
49522                         if (modalName === 'SelectCommand') {
49523                             this.modalOption.templateUrl = 'templates/select-command.html';
49524                             this.modalOption.size = 'lg';
49525                         }
49526                         return this.$uibModal.open(this.modalOption);
49527                     };
49528                     MyModal.prototype.selectCommand = function () {
49529                         this.modalOption.templateUrl = 'templates/select-command.html';
49530                         this.modalOption.controller = 'selectCommandController';
49531                         this.modalOption.controllerAs = 'c';
49532                         this.modalOption.size = 'lg';
49533                         return this.$uibModal.open(this.modalOption);
49534                     };
49535                     MyModal.prototype.preview = function () {
49536                         this.modalOption.templateUrl = 'templates/preview.html';
49537                         this.modalOption.controller = 'previewController';
49538                         this.modalOption.controllerAs = 'c';
49539                         this.modalOption.size = 'lg';
49540                         return this.$uibModal.open(this.modalOption);
49541                     };
49542                     MyModal.$inject = ['$uibModal'];
49543                     return MyModal;
49544                 })();
49545                 services.MyModal = MyModal;
49546             })(services = app.services || (app.services = {}));
49547         })(app || (app = {}));
49548         var app;
49549         (function (app) {
49550             var services;
49551             (function (services) {
49552                 var WebSocket = (function () {
49553                     function WebSocket($rootScope) {
49554                         this.$rootScope = $rootScope;
49555                         this.socket = io.connect();
49556                     }
49557                     WebSocket.prototype.on = function (eventName, callback) {
49558                         var socket = this.socket;
49559                         var rootScope = this.$rootScope;
49560                         socket.on(eventName, function () {
49561                             var args = arguments;
49562                             rootScope.$apply(function () {
49563                                 callback.apply(socket, args);
49564                             });
49565                         });
49566                     };
49567                     WebSocket.prototype.emit = function (eventName, data, callback) {
49568                         var socket = this.socket;
49569                         var rootScope = this.$rootScope;
49570                         this.socket.emit(eventName, data, function () {
49571                             var args = arguments;
49572                             rootScope.$apply(function () {
49573                                 if (callback)
49574                                     callback.apply(socket, args);
49575                             });
49576                         });
49577                     };
49578                     return WebSocket;
49579                 })();
49580                 services.WebSocket = WebSocket;
49581             })(services = app.services || (app.services = {}));
49582         })(app || (app = {}));
49583         var app;
49584         (function (app) {
49585             var services;
49586             (function (services) {
49587                 var Console = (function () {
49588                     function Console(WebSocket, $rootScope) {
49589                         this.WebSocket = WebSocket;
49590                         this.$rootScope = $rootScope;
49591                         this.WebSocket = WebSocket;
49592                         this.$rootScope = $rootScope;
49593                         this.directiveIDs = [];
49594                         var directiveIDs = this.directiveIDs;
49595                         this.WebSocket.on('console', function (d) {
49596                             var id = d.id;
49597                             var message = d.message;
49598                             if (directiveIDs.indexOf(id) > -1) {
49599                                 $rootScope.$emit(id, message);
49600                             }
49601                         });
49602                     }
49603                     Console.prototype.addDirective = function (id) {
49604                         if (!(this.directiveIDs.indexOf(id) > -1)) {
49605                             this.directiveIDs.push(id);
49606                         }
49607                     };
49608                     Console.prototype.removeDirective = function (id) {
49609                         var i = this.directiveIDs.indexOf(id);
49610                         if (i > -1) {
49611                             this.directiveIDs.splice(i, 1);
49612                         }
49613                     };
49614                     Console.prototype.showIDs = function () {
49615                         console.log(this.directiveIDs);
49616                     };
49617                     return Console;
49618                 })();
49619                 services.Console = Console;
49620             })(services = app.services || (app.services = {}));
49621         })(app || (app = {}));
49622         var app;
49623         (function (app) {
49624             var directives;
49625             (function (directives) {
49626                 var Command = (function () {
49627                     function Command() {
49628                         this.restrict = 'E';
49629                         this.replace = true;
49630                         this.scope = true;
49631                         this.controller = 'commandController';
49632                         this.controllerAs = 'ctrl';
49633                         this.bindToController = {
49634                             index: '=',
49635                             name: '=',
49636                             remove: '&',
49637                             list: '='
49638                         };
49639                         this.templateUrl = 'templates/command.html';
49640                     }
49641                     Command.Factory = function () {
49642                         var directive = function () {
49643                             return new Command();
49644                         };
49645                         directive.$inject = [];
49646                         return directive;
49647                     };
49648                     return Command;
49649                 })();
49650                 directives.Command = Command;
49651                 var CommandController = (function () {
49652                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
49653                         this.APIEndPoint = APIEndPoint;
49654                         this.$scope = $scope;
49655                         this.MyModal = MyModal;
49656                         this.WebSocket = WebSocket;
49657                         this.$window = $window;
49658                         this.$rootScope = $rootScope;
49659                         this.Console = Console;
49660                         var controller = this;
49661                         this.APIEndPoint
49662                             .getOptionControlFile(this.name)
49663                             .$promise
49664                             .then(function (result) {
49665                             controller.options = result.info;
49666                         });
49667                         this.APIEndPoint
49668                             .getDirectories()
49669                             .$promise
49670                             .then(function (result) {
49671                             controller.dirs = result.info;
49672                         });
49673                         this.heading = "[" + this.index + "]: dcdFilePrint";
49674                         this.isOpen = true;
49675                         this.$scope.$on('close', function () {
49676                             controller.isOpen = false;
49677                         });
49678                         function guid() {
49679                             function s4() {
49680                                 return Math.floor((1 + Math.random()) * 0x10000)
49681                                     .toString(16)
49682                                     .substring(1);
49683                             }
49684                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
49685                                 s4() + '-' + s4() + s4() + s4();
49686                         }
49687                         this.uuid = guid();
49688                         this.Console.addDirective(this.uuid);
49689                         this.Console.showIDs();
49690                     }
49691                     CommandController.prototype.submit = function () {
49692                         var opt = [];
49693                         angular.forEach(this.options, function (option) {
49694                             var obj = {
49695                                 name: option.option,
49696                                 arguments: []
49697                             };
49698                             angular.forEach(option.arg, function (arg) {
49699                                 if (arg.input) {
49700                                     if (typeof arg.input === 'object') {
49701                                         obj.arguments.push(arg.input.name);
49702                                     }
49703                                     else {
49704                                         obj.arguments.push(arg.input);
49705                                     }
49706                                 }
49707                             });
49708                             if (obj.arguments.length > 0) {
49709                                 opt.push(obj);
49710                             }
49711                         });
49712                         var execObj = {
49713                             command: this.name,
49714                             workspace: this.workspace.fileId,
49715                             options: opt
49716                         };
49717                         this.APIEndPoint
49718                             .execute(JSON.stringify(execObj))
49719                             .then(function (result) {
49720                             console.log(result);
49721                         });
49722                     };
49723                     CommandController.prototype.removeMySelf = function (index) {
49724                         this.$scope.$destroy();
49725                         this.Console.removeDirective(this.uuid);
49726                         this.remove()(index, this.list);
49727                         this.Console.showIDs();
49728                     };
49729                     CommandController.prototype.reloadFiles = function () {
49730                         var _this = this;
49731                         var fileId = this.workspace.fileId;
49732                         this.APIEndPoint
49733                             .getFiles(fileId)
49734                             .$promise
49735                             .then(function (result) {
49736                             var status = result.status;
49737                             if (status === 'success') {
49738                                 _this.files = result.info;
49739                             }
49740                             else {
49741                                 console.log(result.message);
49742                             }
49743                         });
49744                     };
49745                     CommandController.prototype.debug = function () {
49746                         var div = angular.element(this.$window.document).find("div");
49747                         var consoleTag;
49748                         var parametersTag;
49749                         angular.forEach(div, function (v) {
49750                             if (v.className === "panel-body console") {
49751                                 consoleTag = v;
49752                             }
49753                             else if (v.className === "row parameters-console") {
49754                                 parametersTag = v;
49755                             }
49756                         });
49757                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
49758                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
49759                         consoleTag.style.height = consoleHeight;
49760                         consoleTag.style.width = consoleWidth;
49761                     };
49762                     CommandController.prototype.help = function () {
49763                         this.APIEndPoint
49764                             .help(this.name)
49765                             .then(function (result) {
49766                             console.log(result);
49767                         });
49768                     };
49769                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
49770                     return CommandController;
49771                 })();
49772                 directives.CommandController = CommandController;
49773             })(directives = app.directives || (app.directives = {}));
49774         })(app || (app = {}));
49775         var app;
49776         (function (app) {
49777             var directives;
49778             (function (directives) {
49779                 var HeaderMenu = (function () {
49780                     function HeaderMenu() {
49781                         this.restrict = 'E';
49782                         this.replace = true;
49783                         this.templateUrl = 'templates/header-menu.html';
49784                         this.controller = 'HeaderMenuController';
49785                         this.controllerAs = 'hmc';
49786                         this.scope = true;
49787                     }
49788                     HeaderMenu.Factory = function () {
49789                         var directive = function () {
49790                             return new HeaderMenu();
49791                         };
49792                         return directive;
49793                     };
49794                     return HeaderMenu;
49795                 })();
49796                 directives.HeaderMenu = HeaderMenu;
49797                 var HeaderMenuController = (function () {
49798                     function HeaderMenuController($state) {
49799                         this.$state = $state;
49800                         this.isExecution = this.$state.current.name === 'execution';
49801                         this.isWorkspace = this.$state.current.name === 'workspace';
49802                         this.isHistory = this.$state.current.name === 'history';
49803                     }
49804                     HeaderMenuController.prototype.transit = function (state) {
49805                         this.$state.go(state);
49806                     };
49807                     HeaderMenuController.$inject = ['$state'];
49808                     return HeaderMenuController;
49809                 })();
49810                 directives.HeaderMenuController = HeaderMenuController;
49811             })(directives = app.directives || (app.directives = {}));
49812         })(app || (app = {}));
49813         var app;
49814         (function (app) {
49815             var directives;
49816             (function (directives) {
49817                 var Option = (function () {
49818                     function Option() {
49819                         this.restrict = 'E';
49820                         this.replace = true;
49821                         this.controller = 'optionController';
49822                         this.bindToController = {
49823                             info: '=',
49824                             files: '='
49825                         };
49826                         this.scope = true;
49827                         this.templateUrl = 'templates/option.html';
49828                         this.controllerAs = 'ctrl';
49829                     }
49830                     Option.Factory = function () {
49831                         var directive = function () {
49832                             return new Option();
49833                         };
49834                         directive.$inject = [];
49835                         return directive;
49836                     };
49837                     return Option;
49838                 })();
49839                 directives.Option = Option;
49840                 var OptionController = (function () {
49841                     function OptionController() {
49842                         var controller = this;
49843                         angular.forEach(controller.info.arg, function (arg) {
49844                             if (arg.initialValue) {
49845                                 if (arg.formType === 'number') {
49846                                     arg.input = parseInt(arg.initialValue);
49847                                 }
49848                                 else {
49849                                     arg.input = arg.initialValue;
49850                                 }
49851                             }
49852                         });
49853                     }
49854                     OptionController.$inject = [];
49855                     return OptionController;
49856                 })();
49857                 directives.OptionController = OptionController;
49858             })(directives = app.directives || (app.directives = {}));
49859         })(app || (app = {}));
49860         var app;
49861         (function (app) {
49862             var directives;
49863             (function (directives) {
49864                 var Directory = (function () {
49865                     function Directory() {
49866                         this.restrict = 'E';
49867                         this.replace = true;
49868                         this.controller = 'directoryController';
49869                         this.controllerAs = 'ctrl';
49870                         this.bindToController = {
49871                             info: '=',
49872                             add: '&',
49873                             list: '=',
49874                             files: '='
49875                         };
49876                         this.templateUrl = 'templates/directory.html';
49877                     }
49878                     Directory.Factory = function () {
49879                         var directive = function () {
49880                             return new Directory();
49881                         };
49882                         return directive;
49883                     };
49884                     return Directory;
49885                 })();
49886                 directives.Directory = Directory;
49887                 var DirectoryController = (function () {
49888                     function DirectoryController(APIEndPoint, $scope) {
49889                         this.APIEndPoint = APIEndPoint;
49890                         this.$scope = $scope;
49891                         var controller = this;
49892                         this.APIEndPoint
49893                             .getFiles(this.info.fileId)
49894                             .$promise
49895                             .then(function (result) {
49896                             if (result.status === 'success') {
49897                                 controller.files = result.info;
49898                                 angular.forEach(result.info, function (file) {
49899                                     if (file.fileType === '0') {
49900                                         var o = file;
49901                                         if (controller.info.path === '/') {
49902                                             o.path = '/' + file.name;
49903                                         }
49904                                         else {
49905                                             o.path = controller.info.path + '/' + file.name;
49906                                         }
49907                                         controller.add()(o, controller.list);
49908                                     }
49909                                 });
49910                             }
49911                             ;
49912                         });
49913                     }
49914                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
49915                     return DirectoryController;
49916                 })();
49917                 directives.DirectoryController = DirectoryController;
49918             })(directives = app.directives || (app.directives = {}));
49919         })(app || (app = {}));
49920         var app;
49921         (function (app) {
49922             var controllers;
49923             (function (controllers) {
49924                 var Execution = (function () {
49925                     function Execution(MyModal, $scope) {
49926                         this.MyModal = MyModal;
49927                         this.$scope = $scope;
49928                         this.commandInfoList = [];
49929                     }
49930                     ;
49931                     Execution.prototype.add = function () {
49932                         this.$scope.$broadcast('close');
49933                         var commandInfoList = this.commandInfoList;
49934                         var commandInstance = this.MyModal.selectCommand();
49935                         commandInstance
49936                             .result
49937                             .then(function (command) {
49938                             commandInfoList.push(new app.declares.CommandInfo(command));
49939                         });
49940                     };
49941                     Execution.prototype.open = function () {
49942                         var result = this.MyModal.open('SelectCommand');
49943                         console.log(result);
49944                     };
49945                     Execution.prototype.remove = function (index, list) {
49946                         list.splice(index, 1);
49947                     };
49948                     Execution.prototype.close = function () {
49949                         console.log("close");
49950                     };
49951                     Execution.$inject = ['MyModal', '$scope'];
49952                     return Execution;
49953                 })();
49954                 controllers.Execution = Execution;
49955             })(controllers = app.controllers || (app.controllers = {}));
49956         })(app || (app = {}));
49957         var app;
49958         (function (app) {
49959             var controllers;
49960             (function (controllers) {
49961                 var Workspace = (function () {
49962                     function Workspace($scope, APIEndPoint, MyModal) {
49963                         this.$scope = $scope;
49964                         this.APIEndPoint = APIEndPoint;
49965                         this.MyModal = MyModal;
49966                         this.directoryList = [];
49967                         var controller = this;
49968                         var directoryList = this.directoryList;
49969                         var o = {
49970                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
49971                             name: '',
49972                             parentId: '',
49973                             fileType: '',
49974                             createdAt: '',
49975                             updatedAt: '',
49976                             path: '/'
49977                         };
49978                         directoryList.push(o);
49979                     }
49980                     Workspace.prototype.addDirectory = function (info, directoryList) {
49981                         directoryList.push(info);
49982                     };
49983                     Workspace.prototype.debug = function () {
49984                         this.MyModal.preview();
49985                     };
49986                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
49987                     return Workspace;
49988                 })();
49989                 controllers.Workspace = Workspace;
49990             })(controllers = app.controllers || (app.controllers = {}));
49991         })(app || (app = {}));
49992         var app;
49993         (function (app) {
49994             var controllers;
49995             (function (controllers) {
49996                 var History = (function () {
49997                     function History($scope) {
49998                         this.page = "History";
49999                     }
50000                     History.$inject = ['$scope'];
50001                     return History;
50002                 })();
50003                 controllers.History = History;
50004             })(controllers = app.controllers || (app.controllers = {}));
50005         })(app || (app = {}));
50006         var app;
50007         (function (app) {
50008             var controllers;
50009             (function (controllers) {
50010                 var SelectCommand = (function () {
50011                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
50012                         this.APIEndPoint = APIEndPoint;
50013                         this.$modalInstance = $modalInstance;
50014                         var controller = this;
50015                         this.APIEndPoint
50016                             .getTags()
50017                             .$promise.then(function (result) {
50018                             controller.tags = result.info;
50019                         });
50020                         this.APIEndPoint
50021                             .getCommands()
50022                             .$promise.then(function (result) {
50023                             controller.commands = result.info;
50024                         });
50025                         this.currentTag = 'all';
50026                     }
50027                     SelectCommand.prototype.changeTag = function (tag) {
50028                         this.currentTag = tag;
50029                     };
50030                     SelectCommand.prototype.selectCommand = function (command) {
50031                         this.$modalInstance.close(command);
50032                     };
50033                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50034                     return SelectCommand;
50035                 })();
50036                 controllers.SelectCommand = SelectCommand;
50037             })(controllers = app.controllers || (app.controllers = {}));
50038         })(app || (app = {}));
50039         var app;
50040         (function (app) {
50041             var controllers;
50042             (function (controllers) {
50043                 var Preview = (function () {
50044                     function Preview($scope, APIEndPoint, $modalInstance) {
50045                         this.APIEndPoint = APIEndPoint;
50046                         this.$modalInstance = $modalInstance;
50047                         var controller = this;
50048                         console.log('preview');
50049                     }
50050                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50051                     return Preview;
50052                 })();
50053                 controllers.Preview = Preview;
50054             })(controllers = app.controllers || (app.controllers = {}));
50055         })(app || (app = {}));
50056         var filters;
50057         (function (filters) {
50058             function Tag() {
50059                 return function (commands, tag) {
50060                     var result = [];
50061                     angular.forEach(commands, function (command) {
50062                         var flag = false;
50063                         angular.forEach(command.tags, function (value) {
50064                             if (tag === value)
50065                                 flag = true;
50066                         });
50067                         if (flag)
50068                             result.push(command);
50069                     });
50070                     return result;
50071                 };
50072             }
50073             filters.Tag = Tag;
50074         })(filters || (filters = {}));
50075         var app;
50076         (function (app) {
50077             'use strict';
50078             var appName = 'zephyr';
50079             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
50080             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
50081                 $urlRouterProvider.otherwise('/execution');
50082                 $locationProvider.html5Mode({
50083                     enabled: true,
50084                     requireBase: false
50085                 });
50086                 $stateProvider
50087                     .state('execution', {
50088                     url: '/execution',
50089                     templateUrl: 'templates/execution.html',
50090                     controller: 'executionController',
50091                     controllerAs: 'c'
50092                 })
50093                     .state('workspace', {
50094                     url: '/workspace',
50095                     templateUrl: 'templates/workspace.html',
50096                     controller: 'workspaceController',
50097                     controllerAs: 'c'
50098                 })
50099                     .state('history', {
50100                     url: '/history',
50101                     templateUrl: 'templates/history.html',
50102                     controller: 'historyController',
50103                     controllerAs: 'c'
50104                 });
50105             });
50106             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
50107             app.zephyr.service('MyModal', app.services.MyModal);
50108             app.zephyr.service('WebSocket', app.services.WebSocket);
50109             app.zephyr.service('Console', app.services.Console);
50110             app.zephyr.filter('Tag', filters.Tag);
50111             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
50112             app.zephyr.controller('previewController', app.controllers.Preview);
50113             app.zephyr.controller('executionController', app.controllers.Execution);
50114             app.zephyr.controller('workspaceController', app.controllers.Workspace);
50115             app.zephyr.controller('historyController', app.controllers.History);
50116             app.zephyr.controller('commandController', app.directives.CommandController);
50117             app.zephyr.controller('optionController', app.directives.OptionController);
50118             app.zephyr.controller('directoryController', app.directives.DirectoryController);
50119             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
50120             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
50121             app.zephyr.directive('command', app.directives.Command.Factory());
50122             app.zephyr.directive('option', app.directives.Option.Factory());
50123             app.zephyr.directive('directory', app.directives.Directory.Factory());
50124         })(app || (app = {}));
50125
50126
50127 /***/ },
50128 /* 21 */
50129 /***/ function(module, exports) {
50130
50131         var app;
50132         (function (app) {
50133             var declares;
50134             (function (declares) {
50135                 var CommandInfo = (function () {
50136                     function CommandInfo(name) {
50137                         this.name = name;
50138                     }
50139                     return CommandInfo;
50140                 })();
50141                 declares.CommandInfo = CommandInfo;
50142             })(declares = app.declares || (app.declares = {}));
50143         })(app || (app = {}));
50144         var app;
50145         (function (app) {
50146             var services;
50147             (function (services) {
50148                 var APIEndPoint = (function () {
50149                     function APIEndPoint($resource, $http) {
50150                         this.$resource = $resource;
50151                         this.$http = $http;
50152                     }
50153                     APIEndPoint.prototype.resource = function (endPoint, data) {
50154                         var customAction = {
50155                             method: 'GET',
50156                             isArray: false
50157                         };
50158                         var execute = {
50159                             method: 'POST',
50160                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
50161                         };
50162                         return this.$resource(endPoint, {}, { execute: execute });
50163                     };
50164                     APIEndPoint.prototype.getOptionControlFile = function (command) {
50165                         var endPoint = '/api/v1/optionControlFile/' + command;
50166                         return this.resource(endPoint, {}).get();
50167                     };
50168                     APIEndPoint.prototype.getFiles = function (fileId) {
50169                         var endPoint = '/api/v1/workspace';
50170                         if (fileId) {
50171                             endPoint += '/' + fileId;
50172                         }
50173                         return this.resource(endPoint, {}).get();
50174                     };
50175                     APIEndPoint.prototype.getDirectories = function () {
50176                         var endPoint = '/api/v1/all/workspace/directory';
50177                         return this.resource(endPoint, {}).get();
50178                     };
50179                     APIEndPoint.prototype.getTags = function () {
50180                         var endPoint = '/api/v1/tagList';
50181                         return this.resource(endPoint, {}).get();
50182                     };
50183                     APIEndPoint.prototype.getCommands = function () {
50184                         var endPoint = '/api/v1/commandList';
50185                         return this.resource(endPoint, {}).get();
50186                     };
50187                     APIEndPoint.prototype.execute = function (data) {
50188                         var endPoint = '/api/v1/execution';
50189                         var fd = new FormData();
50190                         fd.append('data', data);
50191                         return this.$http.post(endPoint, fd, {
50192                             headers: { 'Content-Type': undefined },
50193                             transformRequest: angular.identity
50194                         });
50195                     };
50196                     APIEndPoint.prototype.debug = function () {
50197                         var endPoint = '/api/v1/debug';
50198                         return this.$http.get(endPoint);
50199                     };
50200                     APIEndPoint.prototype.help = function (command) {
50201                         var endPoint = '/api/v1/help/' + command;
50202                         return this.$http.get(endPoint);
50203                     };
50204                     return APIEndPoint;
50205                 })();
50206                 services.APIEndPoint = APIEndPoint;
50207             })(services = app.services || (app.services = {}));
50208         })(app || (app = {}));
50209         var app;
50210         (function (app) {
50211             var services;
50212             (function (services) {
50213                 var MyModal = (function () {
50214                     function MyModal($uibModal) {
50215                         this.$uibModal = $uibModal;
50216                         this.modalOption = {
50217                             backdrop: true,
50218                             controller: null,
50219                             templateUrl: null,
50220                             size: null
50221                         };
50222                     }
50223                     MyModal.prototype.open = function (modalName) {
50224                         if (modalName === 'SelectCommand') {
50225                             this.modalOption.templateUrl = 'templates/select-command.html';
50226                             this.modalOption.size = 'lg';
50227                         }
50228                         return this.$uibModal.open(this.modalOption);
50229                     };
50230                     MyModal.prototype.selectCommand = function () {
50231                         this.modalOption.templateUrl = 'templates/select-command.html';
50232                         this.modalOption.controller = 'selectCommandController';
50233                         this.modalOption.controllerAs = 'c';
50234                         this.modalOption.size = 'lg';
50235                         return this.$uibModal.open(this.modalOption);
50236                     };
50237                     MyModal.prototype.preview = function () {
50238                         this.modalOption.templateUrl = 'templates/preview.html';
50239                         this.modalOption.controller = 'previewController';
50240                         this.modalOption.controllerAs = 'c';
50241                         this.modalOption.size = 'lg';
50242                         return this.$uibModal.open(this.modalOption);
50243                     };
50244                     MyModal.$inject = ['$uibModal'];
50245                     return MyModal;
50246                 })();
50247                 services.MyModal = MyModal;
50248             })(services = app.services || (app.services = {}));
50249         })(app || (app = {}));
50250         var app;
50251         (function (app) {
50252             var services;
50253             (function (services) {
50254                 var WebSocket = (function () {
50255                     function WebSocket($rootScope) {
50256                         this.$rootScope = $rootScope;
50257                         this.socket = io.connect();
50258                     }
50259                     WebSocket.prototype.on = function (eventName, callback) {
50260                         var socket = this.socket;
50261                         var rootScope = this.$rootScope;
50262                         socket.on(eventName, function () {
50263                             var args = arguments;
50264                             rootScope.$apply(function () {
50265                                 callback.apply(socket, args);
50266                             });
50267                         });
50268                     };
50269                     WebSocket.prototype.emit = function (eventName, data, callback) {
50270                         var socket = this.socket;
50271                         var rootScope = this.$rootScope;
50272                         this.socket.emit(eventName, data, function () {
50273                             var args = arguments;
50274                             rootScope.$apply(function () {
50275                                 if (callback)
50276                                     callback.apply(socket, args);
50277                             });
50278                         });
50279                     };
50280                     return WebSocket;
50281                 })();
50282                 services.WebSocket = WebSocket;
50283             })(services = app.services || (app.services = {}));
50284         })(app || (app = {}));
50285         var app;
50286         (function (app) {
50287             var services;
50288             (function (services) {
50289                 var Console = (function () {
50290                     function Console(WebSocket, $rootScope) {
50291                         this.WebSocket = WebSocket;
50292                         this.$rootScope = $rootScope;
50293                         this.WebSocket = WebSocket;
50294                         this.$rootScope = $rootScope;
50295                         this.directiveIDs = [];
50296                         var directiveIDs = this.directiveIDs;
50297                         this.WebSocket.on('console', function (d) {
50298                             var id = d.id;
50299                             var message = d.message;
50300                             if (directiveIDs.indexOf(id) > -1) {
50301                                 $rootScope.$emit(id, message);
50302                             }
50303                         });
50304                     }
50305                     Console.prototype.addDirective = function (id) {
50306                         if (!(this.directiveIDs.indexOf(id) > -1)) {
50307                             this.directiveIDs.push(id);
50308                         }
50309                     };
50310                     Console.prototype.removeDirective = function (id) {
50311                         var i = this.directiveIDs.indexOf(id);
50312                         if (i > -1) {
50313                             this.directiveIDs.splice(i, 1);
50314                         }
50315                     };
50316                     Console.prototype.showIDs = function () {
50317                         console.log(this.directiveIDs);
50318                     };
50319                     return Console;
50320                 })();
50321                 services.Console = Console;
50322             })(services = app.services || (app.services = {}));
50323         })(app || (app = {}));
50324         var app;
50325         (function (app) {
50326             var directives;
50327             (function (directives) {
50328                 var Command = (function () {
50329                     function Command() {
50330                         this.restrict = 'E';
50331                         this.replace = true;
50332                         this.scope = true;
50333                         this.controller = 'commandController';
50334                         this.controllerAs = 'ctrl';
50335                         this.bindToController = {
50336                             index: '=',
50337                             name: '=',
50338                             remove: '&',
50339                             list: '='
50340                         };
50341                         this.templateUrl = 'templates/command.html';
50342                     }
50343                     Command.Factory = function () {
50344                         var directive = function () {
50345                             return new Command();
50346                         };
50347                         directive.$inject = [];
50348                         return directive;
50349                     };
50350                     return Command;
50351                 })();
50352                 directives.Command = Command;
50353                 var CommandController = (function () {
50354                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
50355                         this.APIEndPoint = APIEndPoint;
50356                         this.$scope = $scope;
50357                         this.MyModal = MyModal;
50358                         this.WebSocket = WebSocket;
50359                         this.$window = $window;
50360                         this.$rootScope = $rootScope;
50361                         this.Console = Console;
50362                         var controller = this;
50363                         this.APIEndPoint
50364                             .getOptionControlFile(this.name)
50365                             .$promise
50366                             .then(function (result) {
50367                             controller.options = result.info;
50368                         });
50369                         this.APIEndPoint
50370                             .getDirectories()
50371                             .$promise
50372                             .then(function (result) {
50373                             controller.dirs = result.info;
50374                         });
50375                         this.heading = "[" + this.index + "]: dcdFilePrint";
50376                         this.isOpen = true;
50377                         this.$scope.$on('close', function () {
50378                             controller.isOpen = false;
50379                         });
50380                         function guid() {
50381                             function s4() {
50382                                 return Math.floor((1 + Math.random()) * 0x10000)
50383                                     .toString(16)
50384                                     .substring(1);
50385                             }
50386                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
50387                                 s4() + '-' + s4() + s4() + s4();
50388                         }
50389                         this.uuid = guid();
50390                         this.Console.addDirective(this.uuid);
50391                         this.Console.showIDs();
50392                     }
50393                     CommandController.prototype.submit = function () {
50394                         var opt = [];
50395                         angular.forEach(this.options, function (option) {
50396                             var obj = {
50397                                 name: option.option,
50398                                 arguments: []
50399                             };
50400                             angular.forEach(option.arg, function (arg) {
50401                                 if (arg.input) {
50402                                     if (typeof arg.input === 'object') {
50403                                         obj.arguments.push(arg.input.name);
50404                                     }
50405                                     else {
50406                                         obj.arguments.push(arg.input);
50407                                     }
50408                                 }
50409                             });
50410                             if (obj.arguments.length > 0) {
50411                                 opt.push(obj);
50412                             }
50413                         });
50414                         var execObj = {
50415                             command: this.name,
50416                             workspace: this.workspace.fileId,
50417                             options: opt
50418                         };
50419                         this.APIEndPoint
50420                             .execute(JSON.stringify(execObj))
50421                             .then(function (result) {
50422                             console.log(result);
50423                         });
50424                     };
50425                     CommandController.prototype.removeMySelf = function (index) {
50426                         this.$scope.$destroy();
50427                         this.Console.removeDirective(this.uuid);
50428                         this.remove()(index, this.list);
50429                         this.Console.showIDs();
50430                     };
50431                     CommandController.prototype.reloadFiles = function () {
50432                         var _this = this;
50433                         var fileId = this.workspace.fileId;
50434                         this.APIEndPoint
50435                             .getFiles(fileId)
50436                             .$promise
50437                             .then(function (result) {
50438                             var status = result.status;
50439                             if (status === 'success') {
50440                                 _this.files = result.info;
50441                             }
50442                             else {
50443                                 console.log(result.message);
50444                             }
50445                         });
50446                     };
50447                     CommandController.prototype.debug = function () {
50448                         var div = angular.element(this.$window.document).find("div");
50449                         var consoleTag;
50450                         var parametersTag;
50451                         angular.forEach(div, function (v) {
50452                             if (v.className === "panel-body console") {
50453                                 consoleTag = v;
50454                             }
50455                             else if (v.className === "row parameters-console") {
50456                                 parametersTag = v;
50457                             }
50458                         });
50459                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
50460                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
50461                         consoleTag.style.height = consoleHeight;
50462                         consoleTag.style.width = consoleWidth;
50463                     };
50464                     CommandController.prototype.help = function () {
50465                         this.APIEndPoint
50466                             .help(this.name)
50467                             .then(function (result) {
50468                             console.log(result);
50469                         });
50470                     };
50471                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
50472                     return CommandController;
50473                 })();
50474                 directives.CommandController = CommandController;
50475             })(directives = app.directives || (app.directives = {}));
50476         })(app || (app = {}));
50477         var app;
50478         (function (app) {
50479             var directives;
50480             (function (directives) {
50481                 var HeaderMenu = (function () {
50482                     function HeaderMenu() {
50483                         this.restrict = 'E';
50484                         this.replace = true;
50485                         this.templateUrl = 'templates/header-menu.html';
50486                         this.controller = 'HeaderMenuController';
50487                         this.controllerAs = 'hmc';
50488                         this.scope = true;
50489                     }
50490                     HeaderMenu.Factory = function () {
50491                         var directive = function () {
50492                             return new HeaderMenu();
50493                         };
50494                         return directive;
50495                     };
50496                     return HeaderMenu;
50497                 })();
50498                 directives.HeaderMenu = HeaderMenu;
50499                 var HeaderMenuController = (function () {
50500                     function HeaderMenuController($state) {
50501                         this.$state = $state;
50502                         this.isExecution = this.$state.current.name === 'execution';
50503                         this.isWorkspace = this.$state.current.name === 'workspace';
50504                         this.isHistory = this.$state.current.name === 'history';
50505                     }
50506                     HeaderMenuController.prototype.transit = function (state) {
50507                         this.$state.go(state);
50508                     };
50509                     HeaderMenuController.$inject = ['$state'];
50510                     return HeaderMenuController;
50511                 })();
50512                 directives.HeaderMenuController = HeaderMenuController;
50513             })(directives = app.directives || (app.directives = {}));
50514         })(app || (app = {}));
50515         var app;
50516         (function (app) {
50517             var directives;
50518             (function (directives) {
50519                 var Option = (function () {
50520                     function Option() {
50521                         this.restrict = 'E';
50522                         this.replace = true;
50523                         this.controller = 'optionController';
50524                         this.bindToController = {
50525                             info: '=',
50526                             files: '='
50527                         };
50528                         this.scope = true;
50529                         this.templateUrl = 'templates/option.html';
50530                         this.controllerAs = 'ctrl';
50531                     }
50532                     Option.Factory = function () {
50533                         var directive = function () {
50534                             return new Option();
50535                         };
50536                         directive.$inject = [];
50537                         return directive;
50538                     };
50539                     return Option;
50540                 })();
50541                 directives.Option = Option;
50542                 var OptionController = (function () {
50543                     function OptionController() {
50544                         var controller = this;
50545                         angular.forEach(controller.info.arg, function (arg) {
50546                             if (arg.initialValue) {
50547                                 if (arg.formType === 'number') {
50548                                     arg.input = parseInt(arg.initialValue);
50549                                 }
50550                                 else {
50551                                     arg.input = arg.initialValue;
50552                                 }
50553                             }
50554                         });
50555                     }
50556                     OptionController.$inject = [];
50557                     return OptionController;
50558                 })();
50559                 directives.OptionController = OptionController;
50560             })(directives = app.directives || (app.directives = {}));
50561         })(app || (app = {}));
50562         var app;
50563         (function (app) {
50564             var directives;
50565             (function (directives) {
50566                 var Directory = (function () {
50567                     function Directory() {
50568                         this.restrict = 'E';
50569                         this.replace = true;
50570                         this.controller = 'directoryController';
50571                         this.controllerAs = 'ctrl';
50572                         this.bindToController = {
50573                             info: '=',
50574                             add: '&',
50575                             list: '=',
50576                             files: '='
50577                         };
50578                         this.templateUrl = 'templates/directory.html';
50579                     }
50580                     Directory.Factory = function () {
50581                         var directive = function () {
50582                             return new Directory();
50583                         };
50584                         return directive;
50585                     };
50586                     return Directory;
50587                 })();
50588                 directives.Directory = Directory;
50589                 var DirectoryController = (function () {
50590                     function DirectoryController(APIEndPoint, $scope) {
50591                         this.APIEndPoint = APIEndPoint;
50592                         this.$scope = $scope;
50593                         var controller = this;
50594                         this.APIEndPoint
50595                             .getFiles(this.info.fileId)
50596                             .$promise
50597                             .then(function (result) {
50598                             if (result.status === 'success') {
50599                                 controller.files = result.info;
50600                                 angular.forEach(result.info, function (file) {
50601                                     if (file.fileType === '0') {
50602                                         var o = file;
50603                                         if (controller.info.path === '/') {
50604                                             o.path = '/' + file.name;
50605                                         }
50606                                         else {
50607                                             o.path = controller.info.path + '/' + file.name;
50608                                         }
50609                                         controller.add()(o, controller.list);
50610                                     }
50611                                 });
50612                             }
50613                             ;
50614                         });
50615                     }
50616                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
50617                     return DirectoryController;
50618                 })();
50619                 directives.DirectoryController = DirectoryController;
50620             })(directives = app.directives || (app.directives = {}));
50621         })(app || (app = {}));
50622         var app;
50623         (function (app) {
50624             var controllers;
50625             (function (controllers) {
50626                 var Execution = (function () {
50627                     function Execution(MyModal, $scope) {
50628                         this.MyModal = MyModal;
50629                         this.$scope = $scope;
50630                         this.commandInfoList = [];
50631                     }
50632                     ;
50633                     Execution.prototype.add = function () {
50634                         this.$scope.$broadcast('close');
50635                         var commandInfoList = this.commandInfoList;
50636                         var commandInstance = this.MyModal.selectCommand();
50637                         commandInstance
50638                             .result
50639                             .then(function (command) {
50640                             commandInfoList.push(new app.declares.CommandInfo(command));
50641                         });
50642                     };
50643                     Execution.prototype.open = function () {
50644                         var result = this.MyModal.open('SelectCommand');
50645                         console.log(result);
50646                     };
50647                     Execution.prototype.remove = function (index, list) {
50648                         list.splice(index, 1);
50649                     };
50650                     Execution.prototype.close = function () {
50651                         console.log("close");
50652                     };
50653                     Execution.$inject = ['MyModal', '$scope'];
50654                     return Execution;
50655                 })();
50656                 controllers.Execution = Execution;
50657             })(controllers = app.controllers || (app.controllers = {}));
50658         })(app || (app = {}));
50659         var app;
50660         (function (app) {
50661             var controllers;
50662             (function (controllers) {
50663                 var Workspace = (function () {
50664                     function Workspace($scope, APIEndPoint, MyModal) {
50665                         this.$scope = $scope;
50666                         this.APIEndPoint = APIEndPoint;
50667                         this.MyModal = MyModal;
50668                         this.directoryList = [];
50669                         var controller = this;
50670                         var directoryList = this.directoryList;
50671                         var o = {
50672                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
50673                             name: '',
50674                             parentId: '',
50675                             fileType: '',
50676                             createdAt: '',
50677                             updatedAt: '',
50678                             path: '/'
50679                         };
50680                         directoryList.push(o);
50681                     }
50682                     Workspace.prototype.addDirectory = function (info, directoryList) {
50683                         directoryList.push(info);
50684                     };
50685                     Workspace.prototype.debug = function () {
50686                         this.MyModal.preview();
50687                     };
50688                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
50689                     return Workspace;
50690                 })();
50691                 controllers.Workspace = Workspace;
50692             })(controllers = app.controllers || (app.controllers = {}));
50693         })(app || (app = {}));
50694         var app;
50695         (function (app) {
50696             var controllers;
50697             (function (controllers) {
50698                 var History = (function () {
50699                     function History($scope) {
50700                         this.page = "History";
50701                     }
50702                     History.$inject = ['$scope'];
50703                     return History;
50704                 })();
50705                 controllers.History = History;
50706             })(controllers = app.controllers || (app.controllers = {}));
50707         })(app || (app = {}));
50708         var app;
50709         (function (app) {
50710             var controllers;
50711             (function (controllers) {
50712                 var SelectCommand = (function () {
50713                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
50714                         this.APIEndPoint = APIEndPoint;
50715                         this.$modalInstance = $modalInstance;
50716                         var controller = this;
50717                         this.APIEndPoint
50718                             .getTags()
50719                             .$promise.then(function (result) {
50720                             controller.tags = result.info;
50721                         });
50722                         this.APIEndPoint
50723                             .getCommands()
50724                             .$promise.then(function (result) {
50725                             controller.commands = result.info;
50726                         });
50727                         this.currentTag = 'all';
50728                     }
50729                     SelectCommand.prototype.changeTag = function (tag) {
50730                         this.currentTag = tag;
50731                     };
50732                     SelectCommand.prototype.selectCommand = function (command) {
50733                         this.$modalInstance.close(command);
50734                     };
50735                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50736                     return SelectCommand;
50737                 })();
50738                 controllers.SelectCommand = SelectCommand;
50739             })(controllers = app.controllers || (app.controllers = {}));
50740         })(app || (app = {}));
50741         var app;
50742         (function (app) {
50743             var controllers;
50744             (function (controllers) {
50745                 var Preview = (function () {
50746                     function Preview($scope, APIEndPoint, $modalInstance) {
50747                         this.APIEndPoint = APIEndPoint;
50748                         this.$modalInstance = $modalInstance;
50749                         var controller = this;
50750                         console.log('preview');
50751                     }
50752                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50753                     return Preview;
50754                 })();
50755                 controllers.Preview = Preview;
50756             })(controllers = app.controllers || (app.controllers = {}));
50757         })(app || (app = {}));
50758         var filters;
50759         (function (filters) {
50760             function Tag() {
50761                 return function (commands, tag) {
50762                     var result = [];
50763                     angular.forEach(commands, function (command) {
50764                         var flag = false;
50765                         angular.forEach(command.tags, function (value) {
50766                             if (tag === value)
50767                                 flag = true;
50768                         });
50769                         if (flag)
50770                             result.push(command);
50771                     });
50772                     return result;
50773                 };
50774             }
50775             filters.Tag = Tag;
50776         })(filters || (filters = {}));
50777         var app;
50778         (function (app) {
50779             'use strict';
50780             var appName = 'zephyr';
50781             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
50782             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
50783                 $urlRouterProvider.otherwise('/execution');
50784                 $locationProvider.html5Mode({
50785                     enabled: true,
50786                     requireBase: false
50787                 });
50788                 $stateProvider
50789                     .state('execution', {
50790                     url: '/execution',
50791                     templateUrl: 'templates/execution.html',
50792                     controller: 'executionController',
50793                     controllerAs: 'c'
50794                 })
50795                     .state('workspace', {
50796                     url: '/workspace',
50797                     templateUrl: 'templates/workspace.html',
50798                     controller: 'workspaceController',
50799                     controllerAs: 'c'
50800                 })
50801                     .state('history', {
50802                     url: '/history',
50803                     templateUrl: 'templates/history.html',
50804                     controller: 'historyController',
50805                     controllerAs: 'c'
50806                 });
50807             });
50808             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
50809             app.zephyr.service('MyModal', app.services.MyModal);
50810             app.zephyr.service('WebSocket', app.services.WebSocket);
50811             app.zephyr.service('Console', app.services.Console);
50812             app.zephyr.filter('Tag', filters.Tag);
50813             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
50814             app.zephyr.controller('previewController', app.controllers.Preview);
50815             app.zephyr.controller('executionController', app.controllers.Execution);
50816             app.zephyr.controller('workspaceController', app.controllers.Workspace);
50817             app.zephyr.controller('historyController', app.controllers.History);
50818             app.zephyr.controller('commandController', app.directives.CommandController);
50819             app.zephyr.controller('optionController', app.directives.OptionController);
50820             app.zephyr.controller('directoryController', app.directives.DirectoryController);
50821             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
50822             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
50823             app.zephyr.directive('command', app.directives.Command.Factory());
50824             app.zephyr.directive('option', app.directives.Option.Factory());
50825             app.zephyr.directive('directory', app.directives.Directory.Factory());
50826         })(app || (app = {}));
50827
50828
50829 /***/ },
50830 /* 22 */
50831 /***/ function(module, exports) {
50832
50833         var app;
50834         (function (app) {
50835             var declares;
50836             (function (declares) {
50837                 var CommandInfo = (function () {
50838                     function CommandInfo(name) {
50839                         this.name = name;
50840                     }
50841                     return CommandInfo;
50842                 })();
50843                 declares.CommandInfo = CommandInfo;
50844             })(declares = app.declares || (app.declares = {}));
50845         })(app || (app = {}));
50846         var app;
50847         (function (app) {
50848             var services;
50849             (function (services) {
50850                 var APIEndPoint = (function () {
50851                     function APIEndPoint($resource, $http) {
50852                         this.$resource = $resource;
50853                         this.$http = $http;
50854                     }
50855                     APIEndPoint.prototype.resource = function (endPoint, data) {
50856                         var customAction = {
50857                             method: 'GET',
50858                             isArray: false
50859                         };
50860                         var execute = {
50861                             method: 'POST',
50862                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
50863                         };
50864                         return this.$resource(endPoint, {}, { execute: execute });
50865                     };
50866                     APIEndPoint.prototype.getOptionControlFile = function (command) {
50867                         var endPoint = '/api/v1/optionControlFile/' + command;
50868                         return this.resource(endPoint, {}).get();
50869                     };
50870                     APIEndPoint.prototype.getFiles = function (fileId) {
50871                         var endPoint = '/api/v1/workspace';
50872                         if (fileId) {
50873                             endPoint += '/' + fileId;
50874                         }
50875                         return this.resource(endPoint, {}).get();
50876                     };
50877                     APIEndPoint.prototype.getDirectories = function () {
50878                         var endPoint = '/api/v1/all/workspace/directory';
50879                         return this.resource(endPoint, {}).get();
50880                     };
50881                     APIEndPoint.prototype.getTags = function () {
50882                         var endPoint = '/api/v1/tagList';
50883                         return this.resource(endPoint, {}).get();
50884                     };
50885                     APIEndPoint.prototype.getCommands = function () {
50886                         var endPoint = '/api/v1/commandList';
50887                         return this.resource(endPoint, {}).get();
50888                     };
50889                     APIEndPoint.prototype.execute = function (data) {
50890                         var endPoint = '/api/v1/execution';
50891                         var fd = new FormData();
50892                         fd.append('data', data);
50893                         return this.$http.post(endPoint, fd, {
50894                             headers: { 'Content-Type': undefined },
50895                             transformRequest: angular.identity
50896                         });
50897                     };
50898                     APIEndPoint.prototype.debug = function () {
50899                         var endPoint = '/api/v1/debug';
50900                         return this.$http.get(endPoint);
50901                     };
50902                     APIEndPoint.prototype.help = function (command) {
50903                         var endPoint = '/api/v1/help/' + command;
50904                         return this.$http.get(endPoint);
50905                     };
50906                     return APIEndPoint;
50907                 })();
50908                 services.APIEndPoint = APIEndPoint;
50909             })(services = app.services || (app.services = {}));
50910         })(app || (app = {}));
50911         var app;
50912         (function (app) {
50913             var services;
50914             (function (services) {
50915                 var MyModal = (function () {
50916                     function MyModal($uibModal) {
50917                         this.$uibModal = $uibModal;
50918                         this.modalOption = {
50919                             backdrop: true,
50920                             controller: null,
50921                             templateUrl: null,
50922                             size: null
50923                         };
50924                     }
50925                     MyModal.prototype.open = function (modalName) {
50926                         if (modalName === 'SelectCommand') {
50927                             this.modalOption.templateUrl = 'templates/select-command.html';
50928                             this.modalOption.size = 'lg';
50929                         }
50930                         return this.$uibModal.open(this.modalOption);
50931                     };
50932                     MyModal.prototype.selectCommand = function () {
50933                         this.modalOption.templateUrl = 'templates/select-command.html';
50934                         this.modalOption.controller = 'selectCommandController';
50935                         this.modalOption.controllerAs = 'c';
50936                         this.modalOption.size = 'lg';
50937                         return this.$uibModal.open(this.modalOption);
50938                     };
50939                     MyModal.prototype.preview = function () {
50940                         this.modalOption.templateUrl = 'templates/preview.html';
50941                         this.modalOption.controller = 'previewController';
50942                         this.modalOption.controllerAs = 'c';
50943                         this.modalOption.size = 'lg';
50944                         return this.$uibModal.open(this.modalOption);
50945                     };
50946                     MyModal.$inject = ['$uibModal'];
50947                     return MyModal;
50948                 })();
50949                 services.MyModal = MyModal;
50950             })(services = app.services || (app.services = {}));
50951         })(app || (app = {}));
50952         var app;
50953         (function (app) {
50954             var services;
50955             (function (services) {
50956                 var WebSocket = (function () {
50957                     function WebSocket($rootScope) {
50958                         this.$rootScope = $rootScope;
50959                         this.socket = io.connect();
50960                     }
50961                     WebSocket.prototype.on = function (eventName, callback) {
50962                         var socket = this.socket;
50963                         var rootScope = this.$rootScope;
50964                         socket.on(eventName, function () {
50965                             var args = arguments;
50966                             rootScope.$apply(function () {
50967                                 callback.apply(socket, args);
50968                             });
50969                         });
50970                     };
50971                     WebSocket.prototype.emit = function (eventName, data, callback) {
50972                         var socket = this.socket;
50973                         var rootScope = this.$rootScope;
50974                         this.socket.emit(eventName, data, function () {
50975                             var args = arguments;
50976                             rootScope.$apply(function () {
50977                                 if (callback)
50978                                     callback.apply(socket, args);
50979                             });
50980                         });
50981                     };
50982                     return WebSocket;
50983                 })();
50984                 services.WebSocket = WebSocket;
50985             })(services = app.services || (app.services = {}));
50986         })(app || (app = {}));
50987         var app;
50988         (function (app) {
50989             var services;
50990             (function (services) {
50991                 var Console = (function () {
50992                     function Console(WebSocket, $rootScope) {
50993                         this.WebSocket = WebSocket;
50994                         this.$rootScope = $rootScope;
50995                         this.WebSocket = WebSocket;
50996                         this.$rootScope = $rootScope;
50997                         this.directiveIDs = [];
50998                         var directiveIDs = this.directiveIDs;
50999                         this.WebSocket.on('console', function (d) {
51000                             var id = d.id;
51001                             var message = d.message;
51002                             if (directiveIDs.indexOf(id) > -1) {
51003                                 $rootScope.$emit(id, message);
51004                             }
51005                         });
51006                     }
51007                     Console.prototype.addDirective = function (id) {
51008                         if (!(this.directiveIDs.indexOf(id) > -1)) {
51009                             this.directiveIDs.push(id);
51010                         }
51011                     };
51012                     Console.prototype.removeDirective = function (id) {
51013                         var i = this.directiveIDs.indexOf(id);
51014                         if (i > -1) {
51015                             this.directiveIDs.splice(i, 1);
51016                         }
51017                     };
51018                     Console.prototype.showIDs = function () {
51019                         console.log(this.directiveIDs);
51020                     };
51021                     return Console;
51022                 })();
51023                 services.Console = Console;
51024             })(services = app.services || (app.services = {}));
51025         })(app || (app = {}));
51026         var app;
51027         (function (app) {
51028             var directives;
51029             (function (directives) {
51030                 var Command = (function () {
51031                     function Command() {
51032                         this.restrict = 'E';
51033                         this.replace = true;
51034                         this.scope = true;
51035                         this.controller = 'commandController';
51036                         this.controllerAs = 'ctrl';
51037                         this.bindToController = {
51038                             index: '=',
51039                             name: '=',
51040                             remove: '&',
51041                             list: '='
51042                         };
51043                         this.templateUrl = 'templates/command.html';
51044                     }
51045                     Command.Factory = function () {
51046                         var directive = function () {
51047                             return new Command();
51048                         };
51049                         directive.$inject = [];
51050                         return directive;
51051                     };
51052                     return Command;
51053                 })();
51054                 directives.Command = Command;
51055                 var CommandController = (function () {
51056                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
51057                         this.APIEndPoint = APIEndPoint;
51058                         this.$scope = $scope;
51059                         this.MyModal = MyModal;
51060                         this.WebSocket = WebSocket;
51061                         this.$window = $window;
51062                         this.$rootScope = $rootScope;
51063                         this.Console = Console;
51064                         var controller = this;
51065                         this.APIEndPoint
51066                             .getOptionControlFile(this.name)
51067                             .$promise
51068                             .then(function (result) {
51069                             controller.options = result.info;
51070                         });
51071                         this.APIEndPoint
51072                             .getDirectories()
51073                             .$promise
51074                             .then(function (result) {
51075                             controller.dirs = result.info;
51076                         });
51077                         this.heading = "[" + this.index + "]: dcdFilePrint";
51078                         this.isOpen = true;
51079                         this.$scope.$on('close', function () {
51080                             controller.isOpen = false;
51081                         });
51082                         function guid() {
51083                             function s4() {
51084                                 return Math.floor((1 + Math.random()) * 0x10000)
51085                                     .toString(16)
51086                                     .substring(1);
51087                             }
51088                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
51089                                 s4() + '-' + s4() + s4() + s4();
51090                         }
51091                         this.uuid = guid();
51092                         this.Console.addDirective(this.uuid);
51093                         this.Console.showIDs();
51094                     }
51095                     CommandController.prototype.submit = function () {
51096                         var opt = [];
51097                         angular.forEach(this.options, function (option) {
51098                             var obj = {
51099                                 name: option.option,
51100                                 arguments: []
51101                             };
51102                             angular.forEach(option.arg, function (arg) {
51103                                 if (arg.input) {
51104                                     if (typeof arg.input === 'object') {
51105                                         obj.arguments.push(arg.input.name);
51106                                     }
51107                                     else {
51108                                         obj.arguments.push(arg.input);
51109                                     }
51110                                 }
51111                             });
51112                             if (obj.arguments.length > 0) {
51113                                 opt.push(obj);
51114                             }
51115                         });
51116                         var execObj = {
51117                             command: this.name,
51118                             workspace: this.workspace.fileId,
51119                             options: opt
51120                         };
51121                         this.APIEndPoint
51122                             .execute(JSON.stringify(execObj))
51123                             .then(function (result) {
51124                             console.log(result);
51125                         });
51126                     };
51127                     CommandController.prototype.removeMySelf = function (index) {
51128                         this.$scope.$destroy();
51129                         this.Console.removeDirective(this.uuid);
51130                         this.remove()(index, this.list);
51131                         this.Console.showIDs();
51132                     };
51133                     CommandController.prototype.reloadFiles = function () {
51134                         var _this = this;
51135                         var fileId = this.workspace.fileId;
51136                         this.APIEndPoint
51137                             .getFiles(fileId)
51138                             .$promise
51139                             .then(function (result) {
51140                             var status = result.status;
51141                             if (status === 'success') {
51142                                 _this.files = result.info;
51143                             }
51144                             else {
51145                                 console.log(result.message);
51146                             }
51147                         });
51148                     };
51149                     CommandController.prototype.debug = function () {
51150                         var div = angular.element(this.$window.document).find("div");
51151                         var consoleTag;
51152                         var parametersTag;
51153                         angular.forEach(div, function (v) {
51154                             if (v.className === "panel-body console") {
51155                                 consoleTag = v;
51156                             }
51157                             else if (v.className === "row parameters-console") {
51158                                 parametersTag = v;
51159                             }
51160                         });
51161                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
51162                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
51163                         consoleTag.style.height = consoleHeight;
51164                         consoleTag.style.width = consoleWidth;
51165                     };
51166                     CommandController.prototype.help = function () {
51167                         this.APIEndPoint
51168                             .help(this.name)
51169                             .then(function (result) {
51170                             console.log(result);
51171                         });
51172                     };
51173                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
51174                     return CommandController;
51175                 })();
51176                 directives.CommandController = CommandController;
51177             })(directives = app.directives || (app.directives = {}));
51178         })(app || (app = {}));
51179         var app;
51180         (function (app) {
51181             var directives;
51182             (function (directives) {
51183                 var HeaderMenu = (function () {
51184                     function HeaderMenu() {
51185                         this.restrict = 'E';
51186                         this.replace = true;
51187                         this.templateUrl = 'templates/header-menu.html';
51188                         this.controller = 'HeaderMenuController';
51189                         this.controllerAs = 'hmc';
51190                         this.scope = true;
51191                     }
51192                     HeaderMenu.Factory = function () {
51193                         var directive = function () {
51194                             return new HeaderMenu();
51195                         };
51196                         return directive;
51197                     };
51198                     return HeaderMenu;
51199                 })();
51200                 directives.HeaderMenu = HeaderMenu;
51201                 var HeaderMenuController = (function () {
51202                     function HeaderMenuController($state) {
51203                         this.$state = $state;
51204                         this.isExecution = this.$state.current.name === 'execution';
51205                         this.isWorkspace = this.$state.current.name === 'workspace';
51206                         this.isHistory = this.$state.current.name === 'history';
51207                     }
51208                     HeaderMenuController.prototype.transit = function (state) {
51209                         this.$state.go(state);
51210                     };
51211                     HeaderMenuController.$inject = ['$state'];
51212                     return HeaderMenuController;
51213                 })();
51214                 directives.HeaderMenuController = HeaderMenuController;
51215             })(directives = app.directives || (app.directives = {}));
51216         })(app || (app = {}));
51217         var app;
51218         (function (app) {
51219             var directives;
51220             (function (directives) {
51221                 var Option = (function () {
51222                     function Option() {
51223                         this.restrict = 'E';
51224                         this.replace = true;
51225                         this.controller = 'optionController';
51226                         this.bindToController = {
51227                             info: '=',
51228                             files: '='
51229                         };
51230                         this.scope = true;
51231                         this.templateUrl = 'templates/option.html';
51232                         this.controllerAs = 'ctrl';
51233                     }
51234                     Option.Factory = function () {
51235                         var directive = function () {
51236                             return new Option();
51237                         };
51238                         directive.$inject = [];
51239                         return directive;
51240                     };
51241                     return Option;
51242                 })();
51243                 directives.Option = Option;
51244                 var OptionController = (function () {
51245                     function OptionController() {
51246                         var controller = this;
51247                         angular.forEach(controller.info.arg, function (arg) {
51248                             if (arg.initialValue) {
51249                                 if (arg.formType === 'number') {
51250                                     arg.input = parseInt(arg.initialValue);
51251                                 }
51252                                 else {
51253                                     arg.input = arg.initialValue;
51254                                 }
51255                             }
51256                         });
51257                     }
51258                     OptionController.$inject = [];
51259                     return OptionController;
51260                 })();
51261                 directives.OptionController = OptionController;
51262             })(directives = app.directives || (app.directives = {}));
51263         })(app || (app = {}));
51264         var app;
51265         (function (app) {
51266             var directives;
51267             (function (directives) {
51268                 var Directory = (function () {
51269                     function Directory() {
51270                         this.restrict = 'E';
51271                         this.replace = true;
51272                         this.controller = 'directoryController';
51273                         this.controllerAs = 'ctrl';
51274                         this.bindToController = {
51275                             info: '=',
51276                             add: '&',
51277                             list: '=',
51278                             files: '='
51279                         };
51280                         this.templateUrl = 'templates/directory.html';
51281                     }
51282                     Directory.Factory = function () {
51283                         var directive = function () {
51284                             return new Directory();
51285                         };
51286                         return directive;
51287                     };
51288                     return Directory;
51289                 })();
51290                 directives.Directory = Directory;
51291                 var DirectoryController = (function () {
51292                     function DirectoryController(APIEndPoint, $scope) {
51293                         this.APIEndPoint = APIEndPoint;
51294                         this.$scope = $scope;
51295                         var controller = this;
51296                         this.APIEndPoint
51297                             .getFiles(this.info.fileId)
51298                             .$promise
51299                             .then(function (result) {
51300                             if (result.status === 'success') {
51301                                 controller.files = result.info;
51302                                 angular.forEach(result.info, function (file) {
51303                                     if (file.fileType === '0') {
51304                                         var o = file;
51305                                         if (controller.info.path === '/') {
51306                                             o.path = '/' + file.name;
51307                                         }
51308                                         else {
51309                                             o.path = controller.info.path + '/' + file.name;
51310                                         }
51311                                         controller.add()(o, controller.list);
51312                                     }
51313                                 });
51314                             }
51315                             ;
51316                         });
51317                     }
51318                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
51319                     return DirectoryController;
51320                 })();
51321                 directives.DirectoryController = DirectoryController;
51322             })(directives = app.directives || (app.directives = {}));
51323         })(app || (app = {}));
51324         var app;
51325         (function (app) {
51326             var controllers;
51327             (function (controllers) {
51328                 var Execution = (function () {
51329                     function Execution(MyModal, $scope) {
51330                         this.MyModal = MyModal;
51331                         this.$scope = $scope;
51332                         this.commandInfoList = [];
51333                     }
51334                     ;
51335                     Execution.prototype.add = function () {
51336                         this.$scope.$broadcast('close');
51337                         var commandInfoList = this.commandInfoList;
51338                         var commandInstance = this.MyModal.selectCommand();
51339                         commandInstance
51340                             .result
51341                             .then(function (command) {
51342                             commandInfoList.push(new app.declares.CommandInfo(command));
51343                         });
51344                     };
51345                     Execution.prototype.open = function () {
51346                         var result = this.MyModal.open('SelectCommand');
51347                         console.log(result);
51348                     };
51349                     Execution.prototype.remove = function (index, list) {
51350                         list.splice(index, 1);
51351                     };
51352                     Execution.prototype.close = function () {
51353                         console.log("close");
51354                     };
51355                     Execution.$inject = ['MyModal', '$scope'];
51356                     return Execution;
51357                 })();
51358                 controllers.Execution = Execution;
51359             })(controllers = app.controllers || (app.controllers = {}));
51360         })(app || (app = {}));
51361         var app;
51362         (function (app) {
51363             var controllers;
51364             (function (controllers) {
51365                 var Workspace = (function () {
51366                     function Workspace($scope, APIEndPoint, MyModal) {
51367                         this.$scope = $scope;
51368                         this.APIEndPoint = APIEndPoint;
51369                         this.MyModal = MyModal;
51370                         this.directoryList = [];
51371                         var controller = this;
51372                         var directoryList = this.directoryList;
51373                         var o = {
51374                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
51375                             name: '',
51376                             parentId: '',
51377                             fileType: '',
51378                             createdAt: '',
51379                             updatedAt: '',
51380                             path: '/'
51381                         };
51382                         directoryList.push(o);
51383                     }
51384                     Workspace.prototype.addDirectory = function (info, directoryList) {
51385                         directoryList.push(info);
51386                     };
51387                     Workspace.prototype.debug = function () {
51388                         this.MyModal.preview();
51389                     };
51390                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
51391                     return Workspace;
51392                 })();
51393                 controllers.Workspace = Workspace;
51394             })(controllers = app.controllers || (app.controllers = {}));
51395         })(app || (app = {}));
51396         var app;
51397         (function (app) {
51398             var controllers;
51399             (function (controllers) {
51400                 var History = (function () {
51401                     function History($scope) {
51402                         this.page = "History";
51403                     }
51404                     History.$inject = ['$scope'];
51405                     return History;
51406                 })();
51407                 controllers.History = History;
51408             })(controllers = app.controllers || (app.controllers = {}));
51409         })(app || (app = {}));
51410         var app;
51411         (function (app) {
51412             var controllers;
51413             (function (controllers) {
51414                 var SelectCommand = (function () {
51415                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
51416                         this.APIEndPoint = APIEndPoint;
51417                         this.$modalInstance = $modalInstance;
51418                         var controller = this;
51419                         this.APIEndPoint
51420                             .getTags()
51421                             .$promise.then(function (result) {
51422                             controller.tags = result.info;
51423                         });
51424                         this.APIEndPoint
51425                             .getCommands()
51426                             .$promise.then(function (result) {
51427                             controller.commands = result.info;
51428                         });
51429                         this.currentTag = 'all';
51430                     }
51431                     SelectCommand.prototype.changeTag = function (tag) {
51432                         this.currentTag = tag;
51433                     };
51434                     SelectCommand.prototype.selectCommand = function (command) {
51435                         this.$modalInstance.close(command);
51436                     };
51437                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
51438                     return SelectCommand;
51439                 })();
51440                 controllers.SelectCommand = SelectCommand;
51441             })(controllers = app.controllers || (app.controllers = {}));
51442         })(app || (app = {}));
51443         var app;
51444         (function (app) {
51445             var controllers;
51446             (function (controllers) {
51447                 var Preview = (function () {
51448                     function Preview($scope, APIEndPoint, $modalInstance) {
51449                         this.APIEndPoint = APIEndPoint;
51450                         this.$modalInstance = $modalInstance;
51451                         var controller = this;
51452                         console.log('preview');
51453                     }
51454                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
51455                     return Preview;
51456                 })();
51457                 controllers.Preview = Preview;
51458             })(controllers = app.controllers || (app.controllers = {}));
51459         })(app || (app = {}));
51460         var filters;
51461         (function (filters) {
51462             function Tag() {
51463                 return function (commands, tag) {
51464                     var result = [];
51465                     angular.forEach(commands, function (command) {
51466                         var flag = false;
51467                         angular.forEach(command.tags, function (value) {
51468                             if (tag === value)
51469                                 flag = true;
51470                         });
51471                         if (flag)
51472                             result.push(command);
51473                     });
51474                     return result;
51475                 };
51476             }
51477             filters.Tag = Tag;
51478         })(filters || (filters = {}));
51479         var app;
51480         (function (app) {
51481             'use strict';
51482             var appName = 'zephyr';
51483             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
51484             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
51485                 $urlRouterProvider.otherwise('/execution');
51486                 $locationProvider.html5Mode({
51487                     enabled: true,
51488                     requireBase: false
51489                 });
51490                 $stateProvider
51491                     .state('execution', {
51492                     url: '/execution',
51493                     templateUrl: 'templates/execution.html',
51494                     controller: 'executionController',
51495                     controllerAs: 'c'
51496                 })
51497                     .state('workspace', {
51498                     url: '/workspace',
51499                     templateUrl: 'templates/workspace.html',
51500                     controller: 'workspaceController',
51501                     controllerAs: 'c'
51502                 })
51503                     .state('history', {
51504                     url: '/history',
51505                     templateUrl: 'templates/history.html',
51506                     controller: 'historyController',
51507                     controllerAs: 'c'
51508                 });
51509             });
51510             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
51511             app.zephyr.service('MyModal', app.services.MyModal);
51512             app.zephyr.service('WebSocket', app.services.WebSocket);
51513             app.zephyr.service('Console', app.services.Console);
51514             app.zephyr.filter('Tag', filters.Tag);
51515             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
51516             app.zephyr.controller('previewController', app.controllers.Preview);
51517             app.zephyr.controller('executionController', app.controllers.Execution);
51518             app.zephyr.controller('workspaceController', app.controllers.Workspace);
51519             app.zephyr.controller('historyController', app.controllers.History);
51520             app.zephyr.controller('commandController', app.directives.CommandController);
51521             app.zephyr.controller('optionController', app.directives.OptionController);
51522             app.zephyr.controller('directoryController', app.directives.DirectoryController);
51523             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
51524             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
51525             app.zephyr.directive('command', app.directives.Command.Factory());
51526             app.zephyr.directive('option', app.directives.Option.Factory());
51527             app.zephyr.directive('directory', app.directives.Directory.Factory());
51528         })(app || (app = {}));
51529
51530
51531 /***/ }
51532 /******/ ]);